Initial commit of the MQTT-SN Java client
Change-Id: I53118600bfcca5fa5b66dea688b43c3d35230841
diff --git a/apps/MQTTSN-UDP-Client/.classpath b/apps/MQTTSN-UDP-Client/.classpath
new file mode 100644
index 0000000..8eafb0d
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="samples"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/apps/MQTTSN-UDP-Client/.project b/apps/MQTTSN-UDP-Client/.project
new file mode 100644
index 0000000..bfaa40c
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>MQTT-SN UDP Client</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/apps/MQTTSN-UDP-Client/readme.txt b/apps/MQTTSN-UDP-Client/readme.txt
new file mode 100644
index 0000000..447bf8d
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/readme.txt
@@ -0,0 +1,12 @@
+This package contains the Java source code of an MQTT-SN client that uses UDP to communicate with either
+an MQTT-SN broker, or an MQTT broker via an MQTT-SN gateway.
+
+There are two clients defined:
+
+* org.eclipse.paho.mqttsn.udpclient.MqttsClient.java: this is the main entry point.
+* org.eclipse.paho.mqttsn.udpclient.SimpleMqttsClient.java: this class is based on the MqttsClient mentioned above
+ and provides a simpler API, e.g. no topic registration is required before first publish.
+
+The directory "samples" contains two sample classes which demonstrate how the above two client libraries
+could be used.
+
diff --git a/apps/MQTTSN-UDP-Client/samples/MqttsSampleConsole.java b/apps/MQTTSN-UDP-Client/samples/MqttsSampleConsole.java
new file mode 100644
index 0000000..1ab75cb
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/samples/MqttsSampleConsole.java
@@ -0,0 +1,518 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/*
+ * Sample application for demonstrating how to use the java MQTT-S client
+ *
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.*;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import org.eclipse.paho.mqttsn.udpclient.*;
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.utils.*;
+
+
+public class MqttsSampleConsole implements MqttsCallback {
+
+ private MqttsClient mqClient; // client
+
+ protected String server; // name of server hosting the broker
+ protected int port; // broker's port
+ protected String mqttsClientId; // client id
+ private boolean mqttsCleanStart=false;
+ private short mqttsKeepAliveDuration = 600; // seconds
+
+ private int maxMqttsMsgLength; //bytes
+ private int minMqttsMsgLength; //bytes
+ private int maxRetries;
+ private int ackTime; //seconds
+
+ protected boolean connected; // true if connected to a broker
+ protected Hashtable<Integer, String> topicTable;
+ private String tName;
+
+ private boolean pubFlag; //indicates a pub has to be sent when REGACK is received
+ private String pubTopic;
+ private byte[] pubMsg;
+ private int pubQos;
+ private boolean pubRetained;
+
+ private boolean autoReconnect=false;
+
+ /*
+ * Constructor
+ * initialize fields and connect to broker
+ */
+
+ public MqttsSampleConsole(String server, int port, String clientId, boolean cleanStart,
+ int maxMqttsMsgLength, int minMqttsMsgLength,
+ int maxRetries, int ackWaitingTime, boolean autoReconnect) {
+
+ this.topicTable = new Hashtable<Integer, String>();
+ this.pubFlag = false; this.pubTopic = null;
+ this.server = server;
+ this.port = port;
+ this.mqttsClientId = clientId;
+ this.mqttsCleanStart= cleanStart;
+
+ this.maxMqttsMsgLength= maxMqttsMsgLength;
+ this.minMqttsMsgLength= minMqttsMsgLength;
+ this.maxRetries= maxRetries;
+ this.ackTime= ackWaitingTime;
+
+ this.autoReconnect=autoReconnect;
+
+ this.connected = false;
+
+ mqClient = new MqttsClient (this.server ,this.port,
+ this.maxMqttsMsgLength, this.minMqttsMsgLength,
+ this.maxRetries, this.ackTime, this.autoReconnect);
+ mqClient.registerHandler(this);
+
+ System.out.print("** mqtts java client version "+
+ MqttsClient.version + " started, ");
+ if (autoReconnect) System.out.println("autoreconnect= true");
+ else System.out.println("autoreconnect= false");
+ System.out.println("");
+
+ connect();
+
+ }
+
+ public static void main(String[] args) {
+ String srv = "localhost"; // default gateway
+ int port = 20000; // default port
+ String clientId = "mqtts_console_" + System.currentTimeMillis(); // default client id
+ boolean cleanStart=false;
+
+ int maxMqttsMsgLength=60;
+ int minMqttsMsgLength=2;
+ int maxRetries=2;
+ int ackTime=3;
+ boolean autoReconnect=true;
+ // parse command line arguments -s server -p port -id clientId
+ // and overwrite default values if present
+ int i = 0;
+ String arg;
+ while (i < args.length && args[i].startsWith("-")) {
+ arg = args[i++];
+ if (arg.equals("-s")) {
+ srv = args[i++];
+ }
+ if (arg.equals("-p")) {
+ port = Integer.parseInt(args[i++]);
+ }
+ if (arg.equals("-id")) {
+ clientId = args[i++];
+ }
+ if (arg.equals("-cs")) {
+ int cs=Integer.parseInt(args[i++]);
+ if(cs==0) cleanStart=false; else cleanStart=true;
+ }
+ if (arg.equals("-log")) {
+ try {
+ ClientLogger.setLogFile(args[i++]);
+ } catch (MqttsException e) {
+ e.printStackTrace();
+ }
+ }
+ if (arg.equals("-level")) {
+ ClientLogger.setLogLevel(Integer.parseInt(args[i++]));
+ }
+ if (arg.equals("-auto")) {
+ if (args[i++].equals("0")) autoReconnect=false;
+ else autoReconnect=true;
+ }
+ }
+
+ System.out.println("");
+ System.out.println("** Starting MQTT-S console ... ");
+ // create console and launch the thread
+ MqttsSampleConsole console = new MqttsSampleConsole(srv,port,clientId,cleanStart,
+ maxMqttsMsgLength,minMqttsMsgLength,maxRetries,ackTime,autoReconnect);
+ console.run();
+ }
+
+ public void run() {
+ while (true) {
+ //System.out.println("");
+
+ // read command line from system.in
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String line="";
+ try {
+ line = in.readLine();
+ }
+ catch (IOException e) { // that should never happen
+ System.out.println("** IOException: " + e);
+ System.exit(0);
+ }
+
+ StringTokenizer st = new StringTokenizer(line);
+ String token[]= new String[10];
+ int i=0;
+ while (st.hasMoreTokens()) {
+ token[i] = st.nextToken(); i++;
+ }
+
+ if (i == 0) {
+ printHelp();
+ continue;
+ }
+
+ if (token[0].equals("exit")) terminate();
+ if (token[0].equals("t")) terminate();
+ if (token[0].equals("help")) printHelp();
+ if (token[0].equals("h")) printHelp();
+ if (token[0].equals("d")) disconnect();
+ if (token[0].equals("print")) printTopicTable();
+ if (token[0].equals("c")) {
+ if (!connected) {
+ connect();
+ } else {
+ System.out.println("** already connected to " + server +
+ " as " + mqttsClientId);
+ }
+ }
+
+
+ if (token[0].equals("s") ) {
+ if (connected) {
+ if (token[1] != null) {
+ subscribe(token[1]);
+ } else {
+ System.out.println(">> error: missing topic");
+ }
+ continue;
+ } else {
+ System.out.println(">> disconnected, subscribe not possible!");
+ }
+ }
+
+ if (token[0].equals("u")) {
+ if (connected) {
+ if (token[1] != null) {
+ unsubscribe(token[1]);
+ } else {
+ System.out.println(">> error: missing topic");
+ }
+ continue;
+ } else {
+ System.out.println(">> disconnected, unsubscribe not possible!");
+ }
+ }
+
+ if (token[0].equals("r")) {
+ if (connected) {
+ if (token[1] != null) {
+ register(token[1]);
+ } else {
+ System.out.println(">> error: missing topic");
+ }
+ continue;
+ } else {
+ System.out.println(">> disconnected, register not possible!");
+ }
+ }
+
+
+ if (token[0].equals("p")) {
+ if (connected) {
+ if (token[1]!=null && token[2]!=null) {
+ boolean retained=false;
+ if (token[3] == null) {
+ publish(token[1],token[2],0,retained);
+ } else {
+ publish(token[1],token[2],1,retained);
+ }
+ } else {
+ System.out.println(">> error, pub format is \"p topic msg \"");
+ }
+ }
+ else System.out.println(">> disconnected, publish not possible!");
+ }
+ } //end while
+ } //end run method
+
+ public void connect() {
+ try {
+ if (mqClient == null) {
+ System.out.println("** Starting MQTTS-S java client version "+
+ MqttsClient.version);
+ mqClient = new MqttsClient (this.server ,this.port,
+ maxMqttsMsgLength, minMqttsMsgLength, maxRetries,
+ ackTime);
+ mqClient.registerHandler(this);
+ }
+ // cleanStart= false;
+ //mqClient.connect(this.mqttsClientId,mqttsCleanStart,mqttsKeepAliveDuration);
+ mqClient.connect(this.mqttsClientId,mqttsCleanStart,mqttsKeepAliveDuration,
+ "down",1,this.mqttsClientId,true);
+ } catch (Exception e){
+ connected = false;
+ System.out.println("** connection to " + server + " failed!");
+ System.out.println("** exception: " + e);
+ //System.out.println("Exiting ... ");
+ //System.exit(0);
+ }
+ }
+
+ public void register(String topicName) {
+ mqClient.register(topicName);
+ this.tName = topicName;
+ }
+
+ public void disconnect() {
+ System.out.println("** disconnecting...");
+ if (connected) {
+ try {
+ mqClient.disconnect();
+ //System.out.println("** connection to gateway closed");
+ connected = false;
+ }
+ catch (Exception e) {
+ System.out.println("** cannot disconnect, exception: " + e);
+ }
+ } else {
+ System.out.println("** already disconnected ... ");
+ }
+ }
+
+ public boolean publish(String topic, String msg, int qos, boolean retained) {
+ byte[] message = msg.getBytes();
+
+ return publish(topic, message, qos, retained);
+ }
+
+ public boolean publish(String topic, byte[] msg, int qos, boolean retained) {
+
+ boolean retVal = false;
+
+ Iterator<Integer> iter = topicTable.keySet().iterator();
+ Iterator<String> iterVal = topicTable.values().iterator();
+ Integer ret = new Integer(-1);
+ while (iter.hasNext()) { //check whether topic is in topicTable
+ Integer topicId = (Integer)iter.next();
+ String tname = (String)iterVal.next();
+ if(tname.equals(topic)) {
+ ret = topicId;
+ break;
+ }
+ }
+ int topicID = ret.intValue();
+ if (topicID == -1) { //topic not in topicTable, have to register it
+ register(topic);
+ pubFlag = true; //set the flag and wait for REG ACK
+ pubTopic= topic; //store the values for later publish
+ pubMsg = msg;
+ pubQos = qos;
+ pubRetained = retained;
+ //System.out.println("** topic not in table, have to register it first");
+ } else {
+ try {
+ retVal = mqClient.publish(topicID, msg, qos, retained);
+ //System.out.println("** published: \"" + topic + ": " +
+ // Utils.hexString(msg) + "\"");
+ } catch (Exception e) {
+ System.out.println("** publish exception: " + e);
+ }
+ }
+ return retVal;
+ }
+
+ public void subscribe(String topic) {
+ if (topic != null) {
+ try {
+ mqClient.subscribe(topic,1,0); //topic name
+ }
+ catch (Exception e) {
+ System.out.println("** sub exception: " + e);
+ }
+ }
+ else {
+ System.out.println("** sub error: topic missing!");
+ }
+
+ this.tName = topic;
+
+ }
+
+ public void unsubscribe(String topic) {
+ if (topic != null) {
+ try {
+ mqClient.unSubscribe(topic,0); //topic name
+ }
+ catch (Exception e) {
+ System.out.println("** unsub exception: " + e);
+ }
+ }
+ else {
+ System.out.println("** unsub error: topic missing!");
+ }
+ this.tName = topic;
+ }
+
+ public void terminate() {
+ disconnect();
+ if (mqClient != null) {
+ mqClient.terminate();
+ mqClient = null;
+ System.out.println("** client terminated!");
+ }
+ System.out.println("** exiting ...");
+ System.exit(0);
+ }
+
+ // callback: publishArrived
+ public int publishArrived(boolean dup, int qos, int topicId, byte[] msg ){
+
+ DateFormat df = new SimpleDateFormat("dd.MM HH:mm:ss.SSS");
+ String topic = (String)topicTable.get(new Integer(topicId));
+ //String message = new String(msg);
+
+ if (topic == null) {
+ System.out.println("** PUB with invalid topic id " +topicId +" rejected ...");
+ return 2; //return invalid topic id
+ }
+
+ System.out.print(df.format(new Date()) + " " + topic +": ");
+ //System.out.println(df.format(new Date()) +" >>> " + topic + " msg= " + Utils.hexString(msg));
+ System.out.println(Utils.hexString(msg));
+
+ return 0;
+ }
+
+ private void printHelp() {
+ System.out.println("");
+ System.out.println("Type c for connect, d for disconnect, " +
+ "p for publish, s for subscribe, u for unsubscribe, " +
+ "and t for terminate.");
+ System.out.println("");
+ }
+
+ //call back: CONNECT is sent to broker, waiting for CONNACK
+ public void connectSent() {
+ System.out.println("** CONNECT sent to " + server +" ...");
+ }
+
+ //call back: CONNACK received
+ public void connected() {
+ connected = true;
+ System.out.println("** connected to " + server + ":" + port + " as " + mqttsClientId);
+ }
+
+ //call back: DISCONNECT received
+ public void disconnected(int returnType) {
+ connected= false;
+ switch(returnType) {
+ case MqttsCallback.MQTTS_OK:
+ System.out.println("** disconnected");
+ break;
+ case MqttsCallback.MQTTS_LOST_GATEWAY:
+ System.out.println("** disconnected, no answer from gateway/broker!");
+ break;
+ default:
+ System.out.println("** disconnected, unknown cause= " + returnType);
+ }
+ }
+
+ //call back: PUBACK received
+ public void pubAckReceived(int topicId, int returnCode) {
+ if (returnCode != 0) {
+ System.out.println("** WARNING: puback received with rc="+returnCode);
+ topicTable.clear();
+ } else {
+ System.out.println("** puback received.");
+ }
+ }
+
+ //call back: PUBCOMP received
+ public void pubCompReceived() {
+ System.out.println("** pubcomp received.");
+
+ }
+
+ //callback: REGACK received
+ public void regAckReceived(int topicId, int returnCode) {
+
+ // System.out.println("** registered: topic= " + tName +
+ // " topicId= "+ topicId + " rc= " + returnCode);
+ topicTable.put(new Integer(topicId), tName);
+ tName=null;
+
+ if (pubFlag) {
+ publish(pubTopic, pubMsg, pubQos, pubRetained);
+ pubFlag = false;
+ }
+
+ }
+
+ //callback: REGISTER received
+ public void registerReceived(int topicId, String topicName) {
+ // System.out.println("** REG received: topic= " + topicName +
+ // " topicId= "+ topicId);
+ topicTable.put(new Integer (topicId), topicName);
+ }
+
+ //callback: SUBACK received
+ public void subackReceived(int grantedQos, int topicId, int rc) {
+ if (rc == 0) {
+ System.out.println("** subscribed: topic= " + tName + " qos= "+
+ grantedQos+ " topicId= " +topicId + " rc= " + rc);
+ topicTable.put(new Integer(topicId), tName);
+ tName=null;
+ } else {
+ System.err.println("** SUB rejected: topic= " + tName + " qos= "+
+ grantedQos+ " topicId= " +topicId + " rc= " + rc);
+ }
+ }
+
+ //callback: UNSUBACK received
+ public void unsubackReceived() {
+ System.out.println("** Unsubscribed: topic= "+this.tName);
+ Iterator<Integer> iter = topicTable.keySet().iterator();
+ Iterator<String> iterVal = topicTable.values().iterator();
+ while (iter.hasNext()) {
+ Integer topicId = (Integer)iter.next();
+ String topic = (String)iterVal.next();
+ if (this.tName.equals(topic)) {
+ topicTable.remove(topicId);
+ break;
+ }
+ }
+
+ }
+
+ public void printTopicTable() {
+ Iterator<Integer> iter = topicTable.keySet().iterator();
+ Iterator<String> iterVal = topicTable.values().iterator();
+ int n = 0;
+ System.out.println("");
+ while (iter.hasNext()) {
+ Integer topicId = (Integer)iter.next();
+ String topicName = (String)iterVal.next();
+ System.out.println("n= " + ++n + ", topicId= "+ topicId +
+ ", topic= " + topicName);
+ }
+ }
+
+}
diff --git a/apps/MQTTSN-UDP-Client/samples/MqttsSimpleConsole.java b/apps/MQTTSN-UDP-Client/samples/MqttsSimpleConsole.java
new file mode 100644
index 0000000..2318b20
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/samples/MqttsSimpleConsole.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+
+import org.eclipse.paho.mqttsn.udpclient.SimpleMqttsCallback;
+import org.eclipse.paho.mqttsn.udpclient.SimpleMqttsClient;
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientLogger;
+
+public class MqttsSimpleConsole implements SimpleMqttsCallback {
+
+ private SimpleMqttsClient mqttsClient;
+ private String broker;
+// private int port;
+ private String clientId;
+
+ public MqttsSimpleConsole(String broker, int port, String clientId,
+ boolean cleanStart, int maxMqttsMsgLength, int minMqttsMsgLength,
+ int maxRetries, int ackWaitingTime, boolean autoReconnect) {
+
+ this.broker = broker;
+// this.port = port;
+ this.clientId = clientId;
+
+ mqttsClient = new SimpleMqttsClient(broker, port, maxMqttsMsgLength, minMqttsMsgLength,
+ maxRetries, ackWaitingTime, autoReconnect);
+ mqttsClient.setCallback(this);
+
+ connect();
+ }
+
+
+ private void connect() {
+ boolean cleanStart = true;
+ int keepAlive = 60; //in sec
+ String willTopic = "will";
+ int willQos = 0;
+ String willMsg = "console no more alive";
+ boolean willRetained = true;
+
+ mqttsClient.connect(clientId, cleanStart, keepAlive, willTopic, willQos, willMsg, willRetained);
+
+ if (mqttsClient.isConnected()) {
+ System.out.println("Connected to "+broker+" as "+clientId);
+ } else {
+ System.err.println("Cannot connect to "+broker+" as "+clientId);
+ }
+
+ }
+
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ String srv = "localhost"; // default gateway
+ int port = 20000; // default port
+ String clientId = "mqtts_console"; // default client id
+ boolean cleanStart=true;
+
+ int maxMqttsMsgLength=120;
+ int minMqttsMsgLength=2;
+ int maxRetries=2;
+ int ackWaitingTime=3; //in sec
+ boolean autoReconnect=false;
+
+ // parse command line arguments -s server -p port -id clientId
+ // and overwrite default values if present
+ int i = 0;
+ String arg;
+ while (i < args.length && args[i].startsWith("-")) {
+ arg = args[i++];
+ if (arg.equals("-s")) {
+ srv = args[i++];
+ }
+ if (arg.equals("-p")) {
+ port = Integer.parseInt(args[i++]);
+ }
+ if (arg.equals("-id")) {
+ clientId = args[i++];
+ }
+ if (arg.equals("-cs")) {
+ int cs=Integer.parseInt(args[i++]);
+ if(cs==0) cleanStart=false; else cleanStart=true;
+ }
+ if (arg.equals("-log")) {
+ try {
+ ClientLogger.setLogFile(args[i++]);
+ } catch (MqttsException e) {
+ e.printStackTrace();
+ }
+ }
+ if (arg.equals("-level")) {
+ ClientLogger.setLogLevel(Integer.parseInt(args[i++]));
+ }
+ if (arg.equals("-auto")) {
+ if (args[i++].equals("0")) autoReconnect=false;
+ else autoReconnect=true;
+ }
+ }
+
+ System.out.println("");
+ System.out.println("** Starting MQTT-S console ... ");
+ // create console and launch the thread
+ MqttsSimpleConsole console = new MqttsSimpleConsole(srv,port,clientId,cleanStart,
+ maxMqttsMsgLength,minMqttsMsgLength,maxRetries,ackWaitingTime,autoReconnect);
+
+ console.run();
+
+ }
+
+ public void run() {
+ while (true) {
+ //System.out.println("");
+
+ // read command line from system.in
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String line="";
+ try {
+ line = in.readLine();
+ }
+ catch (IOException e) { // that should never happen
+ System.out.println("** IOException: " + e);
+ System.exit(0);
+ }
+
+ StringTokenizer st = new StringTokenizer(line);
+ String token[]= new String[10];
+ int i=0;
+ while (st.hasMoreTokens()) {
+ token[i] = st.nextToken(); i++;
+ }
+
+ if (i == 0) {
+ printHelp();
+ continue;
+ }
+
+ if (token[0].equals("exit")) terminate();
+ if (token[0].equals("t")) terminate();
+ if (token[0].equals("help")) printHelp();
+ if (token[0].equals("h")) printHelp();
+ if (token[0].equals("d")) disconnect();
+ if (token[0].equals("c")) {
+ if (!mqttsClient.isConnected()) {
+ connect();
+ } else {
+ System.out.println("** already connected to " + broker +
+ " as " + clientId);
+ }
+ }
+
+
+ if (token[0].equals("s") ) {
+ if (mqttsClient.isConnected()) {
+ if (token[1] != null) {
+ mqttsClient.subscribe(token[1]);
+ } else {
+ System.out.println(">> error: missing topic");
+ }
+ continue;
+ } else {
+ System.out.println(">> disconnected, subscribe not possible!");
+ }
+ }
+
+ if (token[0].equals("u")) {
+ if (mqttsClient.isConnected()) {
+ if (token[1] != null) {
+ mqttsClient.unsubscribe(token[1]);
+ } else {
+ System.out.println(">> error: missing topic");
+ }
+ continue;
+ } else {
+ System.out.println(">> disconnected, unsubscribe not possible!");
+ }
+ }
+
+ if (token[0].equals("p")) {
+ if (mqttsClient.isConnected()) {
+ if (token[1]!=null && token[2]!=null) {
+ boolean retained=false;
+ int qos = 0;
+ if (token[3] != null) qos = 1;
+ try {
+ mqttsClient.publish(token[1],token[2].getBytes("UTF-8"),qos,retained);
+ } catch (Exception e) {
+
+ }
+
+ } else {
+ System.out.println(">> error, pub format is \"p topic msg \"");
+ }
+ }
+ else System.out.println(">> disconnected, publish not possible!");
+ }
+ } //end while
+ } //end run method
+
+ private void printHelp() {
+ System.out.println("");
+ System.out.println("Type c for connect, d for disconnect, " +
+ "p for publish, s for subscribe, u for unsubscribe, " +
+ "and t for terminate.");
+ System.out.println("");
+ }
+ public void terminate() {
+ disconnect();
+ if (mqttsClient != null) {
+ mqttsClient.terminate();
+ mqttsClient = null;
+ System.out.println("** client terminated!");
+ }
+ System.out.println("** exiting ...");
+ System.exit(0);
+ }
+ public void disconnect() {
+ System.out.println("** disconnecting...");
+ if (mqttsClient.isConnected()) {
+ try {
+ mqttsClient.disconnect();
+ //System.out.println("** connection to gateway closed");
+ }
+ catch (Exception e) {
+ System.out.println("** cannot disconnect, exception: " + e);
+ }
+ } else {
+ System.out.println("** already disconnected ... ");
+ }
+ }
+
+ public void disconnected(int reason) {
+ System.out.println("** disconnected, reason= " + reason);
+
+ }
+
+
+ public void publishArrived(boolean retain, int qos, String topic, byte[] data) {
+ try {
+ System.out.println("** pubArrived topic= "+topic+", msg= "+ new String(data,"UTF-8"));
+ } catch (Exception e) {
+
+ }
+ }
+
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallback.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallback.java
new file mode 100644
index 0000000..c86f5eb
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallback.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+public interface MqttsCallback {
+
+ public static final int MQTTS_OK = 0xF0;
+ public static final int MQTTS_ERR_STACK_NOT_READY = 0xF1;
+// private static int MQTTS_ERR_DATA_TOO_LONG = 0xF2;
+ public static final int MQTTS_LOST_GATEWAY = 0xF3;
+
+ //public void connectionLost();
+
+ public int publishArrived(boolean retain, int QoS, int topicId, byte[] thisPayload);
+
+ public void connected();
+
+ public void disconnected(int returnType);
+
+ public void unsubackReceived();
+
+ public void subackReceived(int grandesQos, int topicId, int returnCode);
+
+ public void pubCompReceived();
+
+ public void pubAckReceived(int topicId, int returnCode);
+
+ public void regAckReceived(int topicId, int returnCode);
+
+ public void registerReceived(int topicId, String topicName);
+
+ public void connectSent();
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallbackPreDefinedTopicId.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallbackPreDefinedTopicId.java
new file mode 100644
index 0000000..e163f23
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsCallbackPreDefinedTopicId.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+public interface MqttsCallbackPreDefinedTopicId extends MqttsCallback {
+ public int publishArrivedPreDefinedTopicId(boolean retain, int QoS, int topicId, byte[] thisPayload);
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsClient.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsClient.java
new file mode 100644
index 0000000..166acc4
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/MqttsClient.java
@@ -0,0 +1,1206 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+//import java.util.Hashtable;
+
+
+
+
+
+
+
+
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.messages.Message;
+import org.eclipse.paho.mqttsn.udpclient.messages.control.ControlMessage;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsConnack;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsConnect;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsDisconnect;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsMessage;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPingReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPingResp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubComp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubRec;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubRel;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPublish;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsRegack;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsRegister;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsSuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsSubscribe;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsUnsuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsUnsubscribe;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillMsg;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillMsgReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillMsgResp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillTopic;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillTopicReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillTopicResp;
+import org.eclipse.paho.mqttsn.udpclient.timer.TimerService;
+import org.eclipse.paho.mqttsn.udpclient.udp.UDPInterface;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientLogger;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientParameters;
+import org.eclipse.paho.mqttsn.udpclient.utils.MsgQueue;
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+
+public class MqttsClient implements Runnable{
+
+ public static final String version="140217";
+
+ private static final int MQTTS_BACKUP_MESSAGE = 0x00;
+ private static final int MQTTS_BACKUP_SEND_MESSAGE = 0x01;
+
+ private MqttsMessage message = null;
+
+ private int msgId;
+ private ClientState clState;
+ private volatile boolean running;
+
+ private boolean lostGw = false;
+ private MqttsCallback callback = null;
+ private UDPInterface udpInterface = null;
+ private MsgQueue queue = null;
+ private Thread readThread = null;
+ private TimerService timer = null;
+ private ClientParameters clientParms = null;
+
+ private String clientid;
+ private boolean will;
+ private boolean cleanstart;
+ private int keepalive;
+ private String willtopic;
+ private int willQoS;
+ private String willmsg;
+ private boolean willretain;
+
+ private boolean autoReconnect = false;
+
+ int ackMissedCounter = 0;
+
+
+ public MqttsClient(String gatewayAddress, int gatewayPort, int maxMqttsMsgLength, int minMqttsMsgLength,
+ int maxRetries, int ackWaitingTime, boolean autoReconnect){
+
+ InetAddress adr = null;
+ try {
+ adr = InetAddress.getByName(gatewayAddress);
+ clientParms = new ClientParameters();
+ clientParms.setGatewayAddress(adr);
+ clientParms.setGatewayPort(gatewayPort);
+
+ clientParms.setMaxMqttsLength(maxMqttsMsgLength);
+ clientParms.setMinMqttsLength(minMqttsMsgLength);
+ clientParms.setMaxRetries(maxRetries);
+ clientParms.setWaitingTime(ackWaitingTime);
+
+ this.clState = ClientState.NOT_ACTIVE;
+ this.msgId = 1;
+ this.autoReconnect= autoReconnect;
+
+ queue = new MsgQueue();
+ timer = new TimerService(queue);
+
+ udpInterface = new UDPInterface();
+ udpInterface.initialize(queue, clientParms);
+
+ //create thread for reading
+ this.readThread = new Thread (this, "MqttsClient");
+ this.running = true;
+ this.readThread.start();
+
+ String s = null;
+ if (UDPInterface.ENCAPS) s=" with "; else s=" without ";
+ ClientLogger.log(ClientLogger.INFO, "MQTT-S client version "+
+ version + s + ("encapsulation started ..."));
+ System.out.println("MQTT-S client version "+ version + s + ("encapsulation started ..."));
+
+ } catch (MqttsException e) {
+ ClientLogger.log(ClientLogger.ERROR, ""+e);
+ e.printStackTrace();
+ } catch (UnknownHostException e) {
+ ClientLogger.log(ClientLogger.ERROR, ""+e);
+ e.printStackTrace();
+ }
+ }
+
+ public MqttsClient(String gatewayAddress, int gatewayPort,
+ int maxMqttsMsgLength, int minMqttsMsgLength,
+ int maxRetries, int ackWaitingTime) {
+
+ this(gatewayAddress,gatewayPort,maxMqttsMsgLength,minMqttsMsgLength,
+ maxRetries,ackWaitingTime,false);
+
+ }
+
+ public MqttsClient(String gatewayAddress, int gatewayPort) {
+ this(gatewayAddress,gatewayPort,
+ 256, //max mqtts message length
+ 2, //min mqtts message length
+ 2, //max number retries
+ 5, //ack waiting time
+ false); //auto reconnect
+ }
+
+ public MqttsClient(String gatewayAddress, int gatewayPort, boolean auto) {
+ this(gatewayAddress,gatewayPort,
+ 256, //max mqtts message length
+ 2, //min mqtts message length
+ 2, //max number retries
+ 5, //ack waiting time
+ auto); //auto reconnect
+ }
+
+
+
+ /**
+ * Registers the callback handler of the application.
+ * This handler is used to notify the app about the completion of async events.
+ */
+ public void registerHandler(MqttsCallback handler) {
+ this.callback = handler;
+ this.clState = ClientState.WAITING_CONNECT;
+ }
+
+ public boolean connect(String clientid, boolean cleanstart, int keepalive,
+ String willtopic, int willQoS, String willmsg, boolean willretain) {
+
+ if (this.clState != ClientState.WAITING_CONNECT) {
+ ClientLogger.log(ClientLogger.WARN, "connect() ignored!");
+ //System.out.println("mqttsClient>> connect ignored");
+ callback.disconnected(MqttsCallback.MQTTS_ERR_STACK_NOT_READY);
+ return false;
+ }
+
+ this.clientid = clientid;
+ this.cleanstart = cleanstart;
+ this.keepalive = keepalive;
+ this.will = true;
+ this.willtopic = willtopic;
+ this.willQoS = willQoS;
+ this.willmsg = willmsg;
+ this.willretain = willretain;
+
+ clState=ClientState.CONNECTING_TO_GW;
+ mqtts_connecting(this.clientid, this.will, this.cleanstart, this.keepalive);
+ return true;
+ }
+
+ public boolean connect(String clientid, boolean cleanstart, short keepalive){
+
+ if (this.clState != ClientState.WAITING_CONNECT) {
+ ClientLogger.log(ClientLogger.WARN, "connect() ignored!");
+ callback.disconnected(MqttsCallback.MQTTS_ERR_STACK_NOT_READY);
+ return false;
+ }
+
+ this.clientid = clientid;
+ this.cleanstart = cleanstart;
+ this.keepalive = keepalive;
+ this.will = false;
+
+ this.clState= ClientState.CONNECTING_TO_GW;
+ mqtts_connecting(this.clientid, this.will, this.cleanstart, this.keepalive);
+ return true;
+ }
+
+ public boolean disconnect(){
+
+ MqttsDisconnect msg = new MqttsDisconnect();
+
+ switch (this.clState) {
+ case NOT_ACTIVE:
+ case WAITING_CONNECT:
+ ClientLogger.log(ClientLogger.WARN,"already disconnected, disconnect() ignored");
+ break;
+
+ case CONNECTING_TO_GW:
+ case SEARCHING_GW:
+ // no need for sending a DISC since we are not connected
+ this.clState = ClientState.WAITING_CONNECT;
+ timer.unregisterAll();
+ callback.disconnected(MqttsCallback.MQTTS_OK);
+ break;
+
+ case READY:
+ case WAITING_ACK:
+ // send DISC to gw and wait for DISC
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.unregister(ControlMessage.KEEP_ALIVE);
+ this.clState = ClientState.DISCONNECTING;
+ ClientLogger.log(ClientLogger.INFO,"DISCONNECT sent: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ public boolean publish(int topicId, byte[] message, int qos, boolean retain){
+ return publish(0, topicId, message, qos, retain);
+ }
+ public boolean publish(int topicIdType, int topicId, byte[] message, int qos, boolean retain){
+
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, publish() ignored! "+"Client state = "+ this.clState);
+ return false;
+ }
+
+ MqttsPublish msg = new MqttsPublish();
+
+ switch (qos) {
+ case 2:
+ msg.setQos(qos);
+ int id = getNewMsgId();
+ msg.setMsgId(id);
+ break;
+
+ case 1:
+ msg.setQos(qos);
+ id = getNewMsgId();
+ msg.setMsgId(id);
+ break;
+
+ default:
+ msg.setQos(qos);
+ msg.setMsgId(0);
+ break;
+ }
+
+ msg.setRetain(retain);
+ msg.setTopicId(topicId);
+ msg.setTopicIdType(topicIdType);
+ msg.setData(message);
+
+
+ if(qos !=0){
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+ clState= ClientState.WAITING_ACK;
+ }
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send PUBLISH to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public boolean subscribe(String topicName, int qos, int topicIdType){
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, subscribe() ignored!");
+ return false;
+ }
+
+ MqttsSubscribe msg = new MqttsSubscribe();
+ msg.setQos(qos);
+ if (topicIdType == MqttsMessage.TOPIC_NAME){
+ msg.setTopicIdType(MqttsMessage.TOPIC_NAME);
+ msg.setTopicName(topicName);
+ }
+ if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ msg.setTopicIdType(MqttsMessage.SHORT_TOPIC_NAME);
+ msg.setShortTopicName(topicName);
+ }
+
+ int id = getNewMsgId();
+ msg.setMsgId(id);
+
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ clState= ClientState.WAITING_ACK;
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send SUBSCRIBE to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public boolean subscribe(int topicId, int qos){
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, subscribe2() ignored!");
+ return false;
+ }
+
+ MqttsSubscribe msg = new MqttsSubscribe();
+ msg.setQos(qos);
+ msg.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);
+ msg.setPredefinedTopicId(topicId);
+ int id = getNewMsgId();
+ msg.setMsgId(id);
+
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ clState= ClientState.WAITING_ACK;
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send SUBSCRIBE to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public boolean unSubscribe(String topicName, int topicIdType){
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, unsubscribe1() ignored!");
+ return false;
+ }
+
+ MqttsUnsubscribe msg= new MqttsUnsubscribe();
+
+ if (topicIdType == MqttsMessage.TOPIC_NAME){
+ msg.setTopicIdType(MqttsMessage.TOPIC_NAME);
+ msg.setTopicName(topicName);
+ }
+ if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ msg.setTopicIdType(MqttsMessage.SHORT_TOPIC_NAME);
+ msg.setShortTopicName(topicName);
+ }
+
+ int id = getNewMsgId();
+ msg.setMsgId(id);
+
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ clState= ClientState.WAITING_ACK;
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send UNSUBSCRIBE to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public boolean unSubscribe(int topicId){
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, subscribe2() ignored!");
+ return false;
+ }
+
+ MqttsUnsubscribe msg= new MqttsUnsubscribe();
+
+ msg.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);
+ msg.setPredefinedTopicId(topicId);
+ int id = getNewMsgId();
+ msg.setMsgId(id);
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ clState= ClientState.WAITING_ACK;
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send UNSUBSCRIBE to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public boolean register(String topicName){
+ if (this.clState != ClientState.READY) {
+ ClientLogger.log(ClientLogger.WARN, "client not ready, register() ignored! "+this.clState);
+ return false;
+ }
+
+ MqttsRegister msg = new MqttsRegister();
+ msg.setTopicId(0);
+ int msgId = getNewMsgId();
+ msg.setMsgId(msgId);
+ msg.setTopicName(topicName);
+
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ /* we waiting for REGACK */
+ clState= ClientState.WAITING_ACK;
+ /* Send the message */
+ ClientLogger.log(ClientLogger.INFO, "Send REGISTER to gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ return true;
+ }
+
+ public void terminate(){
+ // terminate udp reader
+ ClientLogger.log(ClientLogger.INFO, "Closing UDP ...");
+ this.udpInterface.terminate();
+ // unregister all timers
+ ClientLogger.log(ClientLogger.INFO, "Stopping all timers ...");
+ this.timer.terminate();
+ // stop mqtts client
+ ClientLogger.log(ClientLogger.INFO, "Stopping client and closing queue ...");
+ this.running = false;
+ this.queue.close();
+ // wait until thread is terminated.
+ try {
+ this.readThread.join();
+ ClientLogger.log(ClientLogger.INFO, "Client terminated ...");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public ClientParameters getClientParameters() {
+ return clientParms;
+ }
+
+ public void setLogfile(String filename) {
+ try {
+ ClientLogger.setLogFile(filename);
+ } catch (MqttsException e) {
+ System.err.println("MqttsClient: cannot set log filename");
+ e.printStackTrace();
+ }
+ }
+
+ public void setLogLevel(int level) {
+ ClientLogger.setLogLevel(level);
+ }
+
+ public void setWaitingTime(int t) {
+ clientParms.setWaitingTime(t);
+ }
+
+ public int getLocalUDPPort() {
+ return udpInterface.getUdpPort();
+ }
+
+ /******************************************************************************************/
+ /** HANDLING OF MQTTS MESSAGES **/
+ /****************************************************************************************/
+
+ private void handleMqttsMessage(MqttsMessage receivedMsg){
+
+ if (clState == ClientState.NOT_ACTIVE) {
+ ClientLogger.log(ClientLogger.WARN, "Client not started yet, received msg ingored.");
+ return;
+ }
+
+ //get the type of the Mqtts message and handle the message according to that type
+ switch(receivedMsg.getMsgType()){
+ case MqttsMessage.ADVERTISE:
+ //handleMqttsAdvertise((MqttsAdvertise) receivedMsg);
+ break;
+
+ case MqttsMessage.SEARCHGW:
+ //handleMqttsSearchGW((MqttsSearchGW) receivedMsg);
+ break;
+
+ case MqttsMessage.GWINFO:
+ //handleMqttsGWInfo((MqttsGWInfo) receivedMsg);
+ break;
+
+ case MqttsMessage.CONNECT:
+ //we will never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "CONNECT received and ignored!!!");
+ break;
+
+ case MqttsMessage.CONNACK:
+ handleMqttsConnack((MqttsConnack) receivedMsg);
+ break;
+
+ case MqttsMessage.WILLTOPICREQ:
+ handleMqttsWillTopicReq((MqttsWillTopicReq) receivedMsg);
+ break;
+
+ case MqttsMessage.WILLTOPIC:
+ ClientLogger.log(ClientLogger.WARN, "WILLTOPIC received and ignored!!!");
+ break;
+
+ case MqttsMessage.WILLMSGREQ:
+ handleMqttsWillMsgReq((MqttsWillMsgReq) receivedMsg);
+ break;
+
+ case MqttsMessage.WILLMSG:
+ ClientLogger.log(ClientLogger.WARN, "WILLMSG received and ignored!!!");
+ break;
+
+ case MqttsMessage.REGISTER:
+ handleMqttsRegister((MqttsRegister)receivedMsg);
+ break;
+
+ case MqttsMessage.REGACK:
+ handleMqttsRegack((MqttsRegack) receivedMsg);
+ break;
+
+ case MqttsMessage.PUBLISH:
+ handleMqttsPublish((MqttsPublish) receivedMsg);
+ break;
+
+ case MqttsMessage.PUBACK:
+ handleMqttsPuback((MqttsPuback) receivedMsg);
+ break;
+
+ case MqttsMessage.PUBCOMP:
+ handleMqttsPubComp((MqttsPubComp) receivedMsg);
+ break;
+
+ case MqttsMessage.PUBREC:
+ handleMqttsPubRec((MqttsPubRec) receivedMsg);
+ break;
+
+ case MqttsMessage.PUBREL:
+ handleMqttsPubRel((MqttsPubRel) receivedMsg);
+ break;
+
+ case MqttsMessage.SUBSCRIBE:
+ ClientLogger.log(ClientLogger.WARN, "SUBSCRIBE received and ignored!!!");
+ break;
+
+ case MqttsMessage.SUBACK:
+ handleMqttsSuback((MqttsSuback) receivedMsg);
+ break;
+
+ case MqttsMessage.UNSUBSCRIBE:
+ ClientLogger.log(ClientLogger.WARN, "UNSUBSCRIBE and ignored received !!!");
+ break;
+
+ case MqttsMessage.UNSUBACK:
+ handleMqttsUnsuback((MqttsUnsuback) receivedMsg);
+ break;
+
+ case MqttsMessage.PINGREQ:
+ handleMqttsPingReq((MqttsPingReq) receivedMsg);
+ break;
+
+ case MqttsMessage.PINGRESP:
+ handleMqttsPingResp((MqttsPingResp) receivedMsg);
+ break;
+
+ case MqttsMessage.DISCONNECT:
+ handleMqttsDisconnect((MqttsDisconnect) receivedMsg);
+ break;
+
+ case MqttsMessage.WILLTOPICUPD:
+ ClientLogger.log(ClientLogger.WARN, "WILLTOPICUPD received and ignored!!!");
+ break;
+
+ case MqttsMessage.WILLTOPICRESP:
+ handleMqttsWillTopicResp((MqttsWillTopicResp) receivedMsg);
+ break;
+
+ case MqttsMessage.WILLMSGUPD:
+ ClientLogger.log(ClientLogger.WARN, "WILLMSGUPD received and ignored!!!");
+ break;
+
+ case MqttsMessage.WILLMSGRESP:
+ handleMqttsWillMsgResp((MqttsWillMsgResp) receivedMsg);
+ break;
+
+ default:
+ ClientLogger.log(ClientLogger.WARN, "MQTT-S message of unknown type \""
+ + receivedMsg.getMsgType()+"\" received and ignored!!!");
+ break;
+ }
+ }
+
+
+ private void handleMqttsWillTopicResp(MqttsWillTopicResp receivedMsg) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void handleMqttsWillMsgResp(MqttsWillMsgResp receivedMsg) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void ack_rx() {
+ timer.unregister(ControlMessage.ACK);
+ clState= ClientState.READY;
+ if (lostGw) {
+ callback.connected();
+ lostGw = false;
+ }
+ }
+
+
+
+ private void handleMqttsDisconnect(MqttsDisconnect receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "DISCONNECT received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ timer.unregister(ControlMessage.ACK);
+ timer.unregister(ControlMessage.KEEP_ALIVE);
+
+ //hlt 19.03.2009 Because we cannot distinguish
+ //between a new gateway => client data still valid at broker
+ //or a broker restart => client data deleted
+ //it is better to inform app so that app can do a restart
+ //e.g. reissue register and subscriptions
+ clState = ClientState.WAITING_CONNECT;
+ ClientLogger.log(ClientLogger.INFO, "Disconnected, waiting for connect");
+ callback.disconnected(MqttsCallback.MQTTS_OK);
+ }
+
+
+
+ private void handleMqttsPingResp(MqttsPingResp receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO,"PINGRESP received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case WAITING_ACK:
+ ack_rx();
+ break;
+ default:
+ break;
+ }
+ }
+
+
+
+ private void handleMqttsPingReq(MqttsPingReq receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PINGREQ received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+ mqtts_pingresp();
+ }
+
+
+
+ private void handleMqttsUnsuback(MqttsUnsuback receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "UNSUBACK received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case WAITING_ACK:
+ if(receivedMsg.getMsgId() != ((MqttsUnsubscribe)this.message).getMsgId()){
+ ClientLogger.log(ClientLogger.WARN, "MsgId (\""+
+ receivedMsg.getMsgId()+"\") of the received Mqtts UNSUBACK message does not match the MsgId (\""+
+ ((MqttsUnsubscribe)this.message).getMsgId()+
+ "\") of the stored Mqtts UNSUBSCRIBE message. The message cannot be processed.");
+ return;
+ }
+
+ ack_rx();
+ callback.unsubackReceived();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private void handleMqttsSuback(MqttsSuback receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "SUBACK received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case WAITING_ACK:
+ if(receivedMsg.getMsgId() != ((MqttsSubscribe)this.message).getMsgId()){
+ ClientLogger.log(ClientLogger.WARN, "MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts SUBACK message does not match the MsgId (\""+((MqttsSubscribe)this.message).getMsgId()+"\") of the stored Mqtts SUBSCRIBE message. The message cannot be processed.");
+ return;
+ }
+
+ ack_rx();
+ callback.subackReceived(receivedMsg.getGrantedQoS(), receivedMsg.getTopicId(),receivedMsg.getReturnCode());
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private void handleMqttsPubRel(MqttsPubRel receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PUBREL received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+ // TODO procedure for QoS 2 not yet checked
+
+ }
+
+ private void handleMqttsPubRec(MqttsPubRec receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PUBREC received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+
+ // TODO procedure for QoS 2 not yet checked
+
+ switch (this.clState){
+ case WAITING_ACK:
+ timer.unregister(ControlMessage.ACK);
+ mqtts_pubrel(receivedMsg.getMsgId());
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void handleMqttsPubComp(MqttsPubComp receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PUBCOMP received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+
+ // TODO procedure for QoS 2 not yet checked
+
+ switch (this.clState){
+ case WAITING_ACK:
+ ack_rx();
+ callback.pubCompReceived();
+ break;
+ default:
+ break;
+ }
+
+ }
+
+
+
+ private void handleMqttsPuback(MqttsPuback receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PUBACK received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case WAITING_ACK:
+ if(receivedMsg.getMsgId() != ((MqttsPublish)this.message).getMsgId()){
+ ClientLogger.log(ClientLogger.WARN, "MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts PUBACK message does not match the MsgId (\""+((MqttsPublish)this.message).getMsgId()+"\") of the stored Mqtts PUBLISH message. The message cannot be processed.");
+ return;
+ }
+
+ ack_rx();
+ callback.pubAckReceived(receivedMsg.getTopicId(), receivedMsg.getReturnCode());
+
+ break;
+
+ default:
+ if (receivedMsg.getReturnCode() != MqttsMessage.RETURN_CODE_ACCEPTED){
+ callback.pubAckReceived(receivedMsg.getTopicId(), receivedMsg.getReturnCode());
+ }
+ break;
+ }
+ }
+
+ private void handleMqttsPublish(MqttsPublish receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "PUBLISH received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+
+ int returnCode=-1;
+ if (receivedMsg.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID) {
+ if (callback instanceof MqttsCallbackPreDefinedTopicId) {
+ MqttsCallbackPreDefinedTopicId ecb = (MqttsCallbackPreDefinedTopicId)callback;
+ returnCode = ecb.publishArrivedPreDefinedTopicId(receivedMsg.isRetain(), receivedMsg.getQos(),
+ receivedMsg.getTopicId(),receivedMsg.getData());
+ } else {
+ ClientLogger.log(ClientLogger.ERROR, "Unexpected publish with predefined topicId received!");
+ returnCode = MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID;
+ }
+
+ } else {
+ returnCode = callback.publishArrived(receivedMsg.isRetain(), receivedMsg.getQos(),
+ receivedMsg.getTopicId(),receivedMsg.getData());
+ }
+
+ if (receivedMsg.getQos() == 1 || returnCode == MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID) {
+ mqtts_puback (receivedMsg.getTopicId(),receivedMsg.getMsgId(),returnCode);
+ }
+ // TODO procedure for QoS 2 not yet checked
+ }
+
+
+
+ private void handleMqttsRegack(MqttsRegack receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "REGACK received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case WAITING_ACK:
+
+ if (!(this.message instanceof MqttsRegister)) {
+ ClientLogger.log(ClientLogger.ERROR, "Unexpected message received: " + this.message.getMsgType());
+ break;
+ }
+
+ if(receivedMsg.getMsgId() != ((MqttsRegister)this.message).getMsgId()){
+ ClientLogger.log(ClientLogger.WARN, "MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts REGACK message does not match the MsgId (\""+((MqttsRegister)this.message).getMsgId()+"\") of the stored Mqtts REGISTER message. The message cannot be processed.");
+ return;
+ }
+
+ ack_rx();
+ callback.regAckReceived(receivedMsg.getTopicId(), receivedMsg.getReturnCode());
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ private void handleMqttsRegister(MqttsRegister receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "REGISTER received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ mqtts_regack(receivedMsg.getTopicId(), receivedMsg.getMsgId(), MqttsMessage.RETURN_CODE_ACCEPTED);
+ callback.registerReceived(receivedMsg.getTopicId(), receivedMsg.getTopicName());
+ }
+
+
+ private void handleMqttsWillMsgReq(MqttsWillMsgReq receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "WILLMSGREQ received "+
+ Utils.hexString(receivedMsg.toBytes()));
+ timer.unregister(ControlMessage.ACK);
+ mqtts_willmsg();
+ }
+
+ private void handleMqttsWillTopicReq(MqttsWillTopicReq receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "WILLTOPCREQ received: "+
+ Utils.hexString(receivedMsg.toBytes()));
+ timer.unregister(ControlMessage.ACK);
+ mqtts_willtopic();
+ }
+
+
+
+ private void handleMqttsConnack(MqttsConnack receivedMsg) {
+ ClientLogger.log(ClientLogger.INFO, "CONNACK received: " +
+ Utils.hexString(receivedMsg.toBytes()));
+
+ switch (this.clState){
+ case CONNECTING_TO_GW:
+ if (receivedMsg.getReturnCode() == MqttsMessage.RETURN_CODE_ACCEPTED) {
+ timer.unregister(ControlMessage.ACK);
+ clState= ClientState.READY;
+ callback.connected();
+ lostGw = false;
+ } else {
+ clState = ClientState.WAITING_CONNECT;
+ timer.unregister(ControlMessage.ACK);
+ timer.unregister(ControlMessage.KEEP_ALIVE);
+ callback.disconnected(receivedMsg.getReturnCode());
+ }
+ break;
+ default:
+ ClientLogger.log(ClientLogger.WARN,"CONNACK received in state "+ this.clState);
+ break;
+ }
+ }
+
+
+ private int getNewMsgId(){
+ return msgId ++;
+ }
+
+
+
+ /**
+ send a PUBACK message
+ */
+
+ private void mqtts_puback(int topicId, int msgId, int returnCode) {
+ //construct a Mqtts PUBACK message
+ MqttsPuback puback = new MqttsPuback();
+
+ puback.setTopicId(topicId);
+ puback.setMsgId(msgId);
+ puback.setReturnCode(returnCode);
+
+ // re-start keep alive timer and send the message
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ //send the Mqtts PUBACK message to the gateway
+ ClientLogger.log(ClientLogger.INFO, "Sending PUBACK message with \"TopicId\" = \"" +topicId+"\" to the gateway:"+ Utils.hexString(puback.toBytes()));
+ udpInterface.sendMsg(puback);
+ }
+
+ /**
+ send a REGACK message
+
+ */
+ private void mqtts_regack(int topicId, int msgId, int returnCode) {
+
+ //construct a Mqtts REGACK message
+ MqttsRegack regack = new MqttsRegack();
+ regack.setTopicId(topicId);
+ regack.setMsgId(msgId);
+ regack.setReturnCode(returnCode);
+
+ // re-start keep alive timer and send the message*/
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ //send the Mqtts REGACK message to the gateway
+ ClientLogger.log(ClientLogger.INFO, "Sending REGACK message with \"TopicId\" = \"" +topicId+"\" to the gateway :"+ Utils.hexString(regack.toBytes()));
+ udpInterface.sendMsg(regack);
+ }
+
+
+ /**
+ send a PUBREL message
+ */
+ private void mqtts_pubrel(int msgId) {
+ //construct a Mqtts PUBREL message
+ MqttsPubRel msg = new MqttsPubRel();
+ msg.setMsgId(msgId);
+
+ //send the Mqtts PUBREL message
+ ClientLogger.log(ClientLogger.INFO, "Sending PUBREL message to the gateway: "+ Utils.hexString(msg.toBytes()));
+
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+ clState= ClientState.WAITING_ACK;
+
+ /* we are waiting for PUBCOMP */
+ /* TODO What happens if we do not rx a PUBCOMP ? Retransmit PUBREL? */
+ /* backup the message for the ack*/
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ udpInterface.sendMsg(msg);
+ }
+
+
+
+ /**
+ send an PINGREQ message
+ */
+ private void mqtts_pingreq() {
+ //construct a Mqtts PINGREQ message
+ MqttsPingReq msg = new MqttsPingReq();
+
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ //send the Mqtts PINGREQ message to the client
+ ClientLogger.log(ClientLogger.INFO, "Sending Mqtts PINGREQ message to the gateway: "+ Utils.hexString(msg.toBytes()));
+ clState= ClientState.WAITING_ACK;
+ udpInterface.sendMsg(msg);
+ }
+
+ /**
+ send an PINGRESP message
+ */
+ private void mqtts_pingresp() {
+ //construct a Mqtts PINGREQ message
+ MqttsPingResp msg = new MqttsPingResp();
+
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ //send the Mqtts PINGRESP message to the client
+ ClientLogger.log(ClientLogger.INFO, "Sending PINGRESP to the gateway: "+ Utils.hexString(msg.toBytes()));;
+ udpInterface.sendMsg(msg);
+
+ }
+
+ /**
+ send an WILLMSG message
+ */
+ private void mqtts_willmsg() {
+
+ //construct a Mqtts WILLMSG message
+ MqttsWillMsg msg = new MqttsWillMsg();
+ msg.setWillMsg(this.willmsg);
+
+
+ /* backup the message for the ack*/
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* star timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+ ClientLogger.log(ClientLogger.INFO, "Sending WILLMSG to the gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+
+ }
+
+ /**
+ send an WILLTOPIC message
+ */
+ private void mqtts_willtopic() {
+
+ MqttsWillTopic msg = new MqttsWillTopic();
+ msg.setQos(this.willQoS);
+ msg.setRetain(this.willretain);
+ msg.setWillTopic(this.willtopic);
+
+ /* backup the message for the ack*/
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* start timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+ ClientLogger.log(ClientLogger.INFO, "Sending WILLTOPIC to the gateway: "+ Utils.hexString(msg.toBytes()));
+ udpInterface.sendMsg(msg);
+ }
+
+ /**
+ send CONNECT message
+ */
+
+ private void mqtts_connecting(String clientid , boolean will, boolean cleanstart, int keepalive) {
+ MqttsConnect msg = new MqttsConnect();
+ msg.setCleanSession(cleanstart);
+ msg.setClientId(clientid);
+ msg.setDuration(keepalive);
+ msg.setWill(will);
+
+ /* set the value of the keep_alive timer */
+ clientParms.setKeepAlivePeriod(keepalive);
+
+ /* backup the message for the ack */
+ mqtts_backup(MQTTS_BACKUP_MESSAGE, msg);
+
+ /* start ack and keep_alive timers */
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+
+ udpInterface.sendMsg(msg);
+ ClientLogger.log(ClientLogger.INFO, "CONNECT sent to gateway: "+ Utils.hexString(msg.toBytes()));
+
+ callback.connectSent();
+
+ return;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ while (running) {
+ readMsg();
+ }
+ }
+
+
+ private void readMsg() {
+ //read the next available Message from queue
+
+ Message msg = null;
+ try {
+ msg = (Message)queue.get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ if (msg == null) {
+ return;
+ }
+ //get the type of the message that "internal" message carries
+ int type = msg.getType();
+ switch(type){
+ case Message.MQTTS_MSG:
+ ClientLogger.log(ClientLogger.INFO, "Processing an mqtts message ...");
+ handleMqttsMessage(msg.getMqttsMessage());
+ break;
+
+ case Message.CONTROL_MSG:
+ ClientLogger.log(ClientLogger.INFO, "Processing a control message ...");
+ handleControlMessage(msg.getControlMessage());
+ break;
+
+ default:
+ ClientLogger.log(ClientLogger.WARN,"Internal message of unknown type \"" + msg.getType()+"\" received.");
+ break;
+ }
+
+ }
+
+
+ private void handleControlMessage(ControlMessage controlMessage) {
+ switch (controlMessage.getMsgType()) {
+ case ControlMessage.ACK:
+ ClientLogger.log(ClientLogger.INFO, "ACK timeout");
+ ackMissedCounter++;
+
+ if (ackMissedCounter > clientParms.getMaxRetries()) {
+
+ //We log a warnning and inform app
+ ClientLogger.log(ClientLogger.WARN, "Too many ACKs missed, lost gw ...");
+ callback.disconnected(MqttsCallback.MQTTS_LOST_GATEWAY);
+
+ if (autoReconnect) {
+ mqtts_backup(MQTTS_BACKUP_SEND_MESSAGE, null);
+ ackMissedCounter= 0;
+ ClientLogger.log(ClientLogger.WARN, "will try re-connecting ...");
+ } else {
+ timer.unregister(ControlMessage.ACK);
+ timer.unregister(ControlMessage.KEEP_ALIVE);
+ clState = ClientState.WAITING_CONNECT;
+ ClientLogger.log(ClientLogger.WARN, "Waiting for new connect from application ...");
+ }
+
+ } else mqtts_backup(MQTTS_BACKUP_SEND_MESSAGE, null);
+ break;
+
+ case ControlMessage.KEEP_ALIVE:
+ ClientLogger.log(ClientLogger.INFO, "Keep Alive timeout, send PINGREQ");
+ mqtts_pingreq();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private void mqtts_backup(int action, MqttsMessage msg) {
+ switch (action) {
+ case MQTTS_BACKUP_MESSAGE: /* back up message */
+ this.message = msg;
+ ClientLogger.log(ClientLogger.INFO, "Message backup for retransmission");
+ break;
+
+ case MQTTS_BACKUP_SEND_MESSAGE: /* resend message stored in backup */
+ timer.register(ControlMessage.KEEP_ALIVE, clientParms.getKeepAlivePeriod());
+ timer.register(ControlMessage.ACK, clientParms.getWaitingTime());
+ ClientLogger.log(ClientLogger.INFO, "Backup message resent:"+ Utils.hexString(this.message.toBytes()));
+ udpInterface.sendMsg(this.message);
+
+ break;
+
+ default:
+ break;
+ }
+ return;
+ }
+
+
+
+
+ /********************************************************************************/
+ private enum ClientState {
+
+ NOT_ACTIVE,
+ WAITING_CONNECT,
+ CONNECTING_TO_GW,
+ READY,
+
+ WAITING_ACK,
+
+ SEARCHING_GW,
+ DISCONNECTING;
+
+ }
+
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallback.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallback.java
new file mode 100644
index 0000000..2173906
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallback.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+public interface SimpleMqttsCallback {
+ public void publishArrived(boolean ret, int qos, String topic, byte[] msg);
+ public void disconnected(int returnType);
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallbackPreDefinedTopicId.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallbackPreDefinedTopicId.java
new file mode 100644
index 0000000..cc6934a
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsCallbackPreDefinedTopicId.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+public interface SimpleMqttsCallbackPreDefinedTopicId extends SimpleMqttsCallback{
+ public void publishArrivedPreDefinedTopicId(boolean ret, int qos, int topicId, byte[] msg);
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsClient.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsClient.java
new file mode 100644
index 0000000..6adfafd
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/SimpleMqttsClient.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient;
+
+import java.util.Hashtable;
+
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsMessage;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientLogger;
+
+public class SimpleMqttsClient implements MqttsCallbackPreDefinedTopicId {
+ private MqttsClient client = null;
+ private Hashtable<Integer, String> tableIdTopic = new Hashtable<Integer, String>();
+ private Hashtable<String, Integer> tableTopicId = new Hashtable<String, Integer>();
+ private volatile boolean waitConnect = false;
+ private volatile boolean waitRegAck = false;
+ private volatile boolean waitPubAck = false;
+ private String regTopic = null;
+ private volatile boolean waitSubAck = false;
+ private volatile boolean waitUnSubAck = false;
+ private String subTopic = null;
+ private SimpleMqttsCallback callback = null;
+
+ private boolean connected = false;
+
+ public SimpleMqttsClient(String gw) {
+ this(gw, 20000,false);
+ }
+
+ public SimpleMqttsClient(String gw, int port) {
+ this(gw, port, false);
+ }
+
+ public SimpleMqttsClient(String gw, int port, boolean auto) {
+ client = new MqttsClient(gw, port, auto);
+ client.registerHandler(this);
+ }
+
+ public SimpleMqttsClient(String gatewayAddress, int gatewayPort,
+ int maxMqttsMsgLength, int minMqttsMsgLength,
+ int maxRetries, int ackWaitingTime,
+ boolean autoReconnect) {
+ client = new MqttsClient(gatewayAddress, gatewayPort, maxMqttsMsgLength,
+ minMqttsMsgLength, maxRetries, ackWaitingTime, autoReconnect);
+ client.registerHandler(this);
+ }
+
+ public void setCallback(SimpleMqttsCallback callback) {
+ this.callback = callback;
+ }
+
+ public void connect() {
+ connect("" + System.currentTimeMillis());
+ }
+
+ public void connect(String clientId) {
+ boolean cleanstart = true;
+ int keepAlive = 120;
+ connect(clientId, cleanstart, keepAlive);
+ }
+
+ public void connect(String clientId, boolean cleanStart, int keepAlive) {
+ synchronized(this) {
+ waitConnect = true;
+ client.connect(clientId, cleanStart, (short)keepAlive);
+ while(waitConnect) {
+ try { wait(); } catch(InterruptedException ie) {}
+ }
+ }
+ }
+
+ public void connect(String clientId, boolean cleanStart, int keepAlive, String willTopic, int willQos, String willMsg, boolean willRetained) {
+ synchronized(this) {
+ waitConnect = true;
+ client.connect(clientId, cleanStart, (short)keepAlive, willTopic,willQos,willMsg,willRetained);
+ while(waitConnect) {
+ try { wait(); } catch(InterruptedException ie) {}
+ }
+ }
+ }
+
+ //callback when CONNECT is sent to broker
+ public void connectSent() {
+ ClientLogger.info("SimpleClient>> connecting ...");
+ }
+
+ //callback when CONNACK is received
+ public void connected() {
+ ClientLogger.info("SimpleClient>> CONNECT ACK received ...");
+ synchronized(this) {
+ waitConnect = false;
+ connected = true;
+ notifyAll();
+ }
+ }
+
+ //ask client to send a DISCONNECT
+ public void disconnect() {
+ client.disconnect();
+ connected = false;
+ }
+
+ //disconnected from broker
+ public void disconnected(int returnCode) {
+ connected = false;
+ tableIdTopic.clear();
+ tableTopicId.clear();
+ synchronized(this) {
+ if(waitConnect) waitConnect = false;
+ if(waitRegAck) waitRegAck = false;
+ if(waitSubAck) waitSubAck = false;
+ if(waitUnSubAck) waitUnSubAck = false;
+ notifyAll();
+ }
+ callback.disconnected(returnCode);
+ }
+
+ // TODO: not safe for use with multiple threads!
+ public void subscribe(String topic) {
+ if(connected) subscribe(topic, 0);
+ }
+
+ public void subscribe(String topic, int qos) {
+ if(!connected) return;
+ synchronized(this) {
+ waitSubAck = true;
+ subTopic = topic;
+ client.subscribe(topic, qos, 0);
+ while(waitSubAck) {
+ try { wait(); } catch(InterruptedException ie) {}
+ }
+ }
+ }
+
+ public void subackReceived(int grantedQos, int topicId, int returnCode) {
+ synchronized(this) {
+ if(returnCode == MqttsMessage.RETURN_CODE_ACCEPTED) {
+ tableIdTopic.put(new Integer(topicId), this.subTopic);
+ tableTopicId.put(this.subTopic, new Integer(topicId));
+ } else {
+ ClientLogger.warn("SimpleClient>> subscribe rejected ...");
+ }
+ waitSubAck = false;
+ notifyAll();
+ }
+ }
+
+ public void unsubscribe(String topic) {
+ if(!connected) return;
+ synchronized(this) {
+ waitUnSubAck = true;
+ client.unSubscribe(topic, MqttsMessage.TOPIC_NAME);
+ while(waitUnSubAck) {
+ try { wait(); } catch(InterruptedException ie) {}
+ }
+ }
+ }
+
+ public void unsubackReceived() {
+ synchronized(this) {
+ // no need for removing anything from hashtables
+ waitUnSubAck = false;
+ notifyAll();
+ }
+ }
+
+ public void publish(String topic, byte[] data) {
+ if(connected) publish(topic, data, 0, false);
+ }
+
+ public void publish(String topic, byte[] data, int qos, boolean retained) {
+ if(!connected) return;
+
+ //check whether we already have a topicID; if not register first before sending publish
+ int topicID = -1;
+ while(topicID < 0 && connected) {
+ Integer t = (Integer)tableTopicId.get(topic);
+ if(t != null) {
+ topicID = t.intValue(); //we have a topicID
+ } else {
+ waitRegAck = true;
+ regTopic = topic;
+ while(!client.register(topic)); //try until client sends reg
+ synchronized(this) {
+ while(waitRegAck) {
+ try { wait(10000); } catch(InterruptedException ie) {ie.printStackTrace();}
+ }
+ }
+ }
+ }
+ if(connected) {
+ waitPubAck = (qos > 0); //will only wait for puback if qos > 0
+ while(!client.publish(topicID, data, qos, retained)&&connected) {
+ //try {wait(5);} catch (InterruptedException e) {}
+ try {Thread.sleep(2000);} catch (InterruptedException e) {}
+ }
+ synchronized(this) {
+ while(waitPubAck) {
+ try { wait(10000); } catch(InterruptedException ie) {ie.printStackTrace();}
+ }
+ }
+ }
+ }
+
+ //publish using a pre-defined topicId
+ public boolean publish(int topicId, byte[] data, boolean retained) {
+ if (!connected) return false;
+ return client.publish(1, topicId, data, 0, retained);
+ }
+
+ public void regAckReceived(int topicId, int rc) {
+ synchronized(this) {
+ if(rc == MqttsMessage.RETURN_CODE_ACCEPTED) {
+ tableTopicId.put(regTopic, new Integer(topicId));
+ tableIdTopic.put(new Integer(topicId), regTopic);
+ } else {
+ ClientLogger.error("SimpleClient>> Cannot register topic: "+ regTopic);
+ }
+ waitRegAck = false;
+ notifyAll();
+ }
+ }
+
+ public void pubAckReceived(int topicId, int rc) {
+ synchronized(this) {
+ if(rc != 0) {
+ //pub was rejected, remove id and topic from tables
+ String topic = (String)tableIdTopic.get(new Integer(topicId));
+ tableIdTopic.remove(new Integer(topicId));
+ tableTopicId.remove(topic);
+ ClientLogger.error("SimpleClient>> cannot publish, topic: "+ topic);
+ }
+ waitPubAck = false;
+ notifyAll();
+ }
+ }
+
+ public void pubCompReceived() {
+ }
+
+ public void registerReceived(int topicId, String topicName) {
+ tableTopicId.put(topicName, new Integer(topicId));
+ tableIdTopic.put(new Integer(topicId), topicName);
+ }
+
+ public int publishArrived(boolean ret, int qos, int topicId, byte[] thisPayload) {
+ String topic = (String)tableIdTopic.get(new Integer(topicId));
+ if(topic == null) {
+ ClientLogger.warn("SimpleClient>> received pub with unknown topic id: "+topicId);
+ return MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID;
+ }
+ if(callback != null) {
+ callback.publishArrived(ret, qos, topic, thisPayload);
+ }
+ return 0;
+ }
+
+ public int publishArrivedPreDefinedTopicId(boolean retain, int qos, int topicId,
+ byte[] msg) {
+
+ if (callback != null && callback instanceof SimpleMqttsCallbackPreDefinedTopicId) {
+
+ SimpleMqttsCallbackPreDefinedTopicId cb = (SimpleMqttsCallbackPreDefinedTopicId)callback;
+ cb.publishArrivedPreDefinedTopicId(retain,qos,topicId,msg);
+
+ } else {
+ ClientLogger.error("SimpleClient>> Error receiving pub with pre-defined topicId");
+ }
+
+ return 0;
+ }
+
+ public void terminate() {
+ client.terminate();
+ }
+
+ public String getConnection() {
+ String conn;
+ conn = client.getClientParameters().getGatewayAddress().toString();
+ conn = conn + ":" + client.getClientParameters().getGatewayPort();
+ return conn;
+ }
+
+ public void setLogfile(String filename) {
+ client.setLogfile(filename);
+ }
+
+ public void setLogLevel(int level) {
+ client.setLogLevel(level);
+ }
+
+ public void setWaitingTime(int t) {
+ client.setWaitingTime(t);
+ }
+
+ public int getLocalUDPPort() {
+ return client.getLocalUDPPort();
+ }
+
+ public boolean isConnected() {
+ return connected;
+ }
+
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/exceptions/MqttsException.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/exceptions/MqttsException.java
new file mode 100644
index 0000000..1c80d7a
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/exceptions/MqttsException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.exceptions;
+
+public class MqttsException extends Exception{
+ private static final long serialVersionUID = 1L;
+ private Throwable cause = null;
+ /**
+ *
+ */
+ public MqttsException() {
+ super();
+ }
+
+ public MqttsException(String s) {
+ super(s);
+ }
+
+ public MqttsException(Throwable cause) {
+ super( (cause==null)? null : cause.toString() );
+ this.cause = cause;
+ }
+
+ public Throwable getCause(){
+ return this.cause;
+ }
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/Message.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/Message.java
new file mode 100644
index 0000000..be017bc
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/Message.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient.messages;
+
+import org.eclipse.paho.mqttsn.udpclient.messages.control.ControlMessage;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsMessage;
+
+
+public class Message {
+ public static final int MQTTS_MSG = 1;
+ public static final int CONTROL_MSG = 2;
+
+
+ private int type;
+
+ private MqttsMessage mqttsMessage = null;
+ private ControlMessage controlMessage = null;
+
+
+ public Message() {}
+
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public MqttsMessage getMqttsMessage() {
+ return mqttsMessage;
+ }
+
+ public void setMqttsMessage(MqttsMessage mqttsMessage) {
+ this.mqttsMessage = mqttsMessage;
+ }
+
+
+ public ControlMessage getControlMessage() {
+ return controlMessage;
+ }
+
+ public void setControlMessage(ControlMessage controlMessage) {
+ this.controlMessage = controlMessage;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/control/ControlMessage.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/control/ControlMessage.java
new file mode 100644
index 0000000..762191c
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/control/ControlMessage.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient.messages.control;
+
+public class ControlMessage {
+
+ //Control message types
+ public static final int ACK = 1;
+ public static final int KEEP_ALIVE = 2;
+ public static final int WAIT_SEARCHGW = 3;
+ public static final int WAIT_GWINFO = 4;
+
+ public ControlMessage(){}
+
+ private int msgType;
+
+ public int getMsgType() {
+ return msgType;
+ }
+
+ public void setMsgType(int msgType) {
+ this.msgType = msgType;
+ }
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsAdvertise.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsAdvertise.java
new file mode 100644
index 0000000..aa1fef6
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsAdvertise.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts ADVERTISE message.
+ *
+ *
+ */
+public class MqttsAdvertise extends MqttsMessage {
+
+ //Mqtts ADVERTISE fields
+ private int gwId;
+ private long duration;
+
+ /**
+ * MqttsAdvertise constructor.Sets the appropriate message type.
+ */
+ public MqttsAdvertise() {
+ msgType = MqttsMessage.ADVERTISE;
+ }
+
+ /**
+ * MqttsAdvertise constructor.Sets the appropriate message type and constructs
+ * a Mqtts ADVERTISE message from a received byte array.
+ * @param data: The buffer that contains the ADVERTISE message.
+ */
+ public MqttsAdvertise(byte[] data) {
+ msgType = MqttsMessage.ADVERTISE;
+ gwId = (data[2] & 0xFF);
+ duration = ((data[3] & 0xFF) << 8) + (data[4] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the ADVERTISE message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 5;
+ byte[] data = new byte[length];
+ data[0] = (byte) length;
+ data[1] = (byte) msgType;
+ data[2] = (byte) gwId;
+ data[3] = (byte) ((duration >> 8) & 0xFF);
+ data[4] = (byte) (duration & 0xFF);
+ return data;
+ }
+
+ public int getGwId() {
+ return gwId;
+ }
+
+ public void setGwId(int gwId) {
+ this.gwId = gwId;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnack.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnack.java
new file mode 100644
index 0000000..c2f94db
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnack.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsMessage;
+
+/**
+ * This object represents a Mqtts CONNACK message.
+ *
+
+ *
+ */
+public class MqttsConnack extends MqttsMessage {
+ //Mqtts CONNACK fields
+ private int returnCode;
+
+ /**
+ * MqttsConack constructor.Sets the appropriate message type.
+ */
+ public MqttsConnack() {
+ msgType = MqttsMessage.CONNACK;
+ }
+
+ /**
+ * MqttsConack constructor.Sets the appropriate message type and constructs
+ * a Mqtts CONNACK message from a received byte array.
+ * @param data: The buffer that contains the CONNACK message.
+ * (Don't needed in the GW)
+ */
+ public MqttsConnack(byte[] data){
+ msgType = MqttsMessage.CONNACK;
+ returnCode = (data[2] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the CONNACK message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 3;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)returnCode;
+ return data;
+ }
+
+ public int getReturnCode() {
+ return returnCode;
+ }
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnect.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnect.java
new file mode 100644
index 0000000..19a02a0
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsConnect.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts CONNECT message.
+ *
+ *
+ */
+public class MqttsConnect extends MqttsMessage{
+
+ //Mqtts CONNECT fields
+ private boolean will;
+ private boolean cleanSession;
+ private String protocolId;
+ private int duration;
+ private String clientId;
+
+ //Protocol name and protocol version are embedded in the "protocolId" variable.
+ //Mqtts protocol does not use them separately.
+ private String protocolName;
+ private int protocolVersion;
+
+ /**
+ * MqttsConnect constructor.Sets the appropriate message type.
+ */
+ public MqttsConnect() {
+ msgType = MqttsMessage.CONNECT;
+ }
+
+ /**
+ * MqttsConnect constructor.Sets the appropriate message type and constructs
+ * a Mqtts CONNECT message from a received byte array.
+ * @param data: The buffer that contains the CONNECT message.
+ */
+ public MqttsConnect(byte[] data) {
+ msgType = MqttsMessage.CONNECT;
+ will = ((data[2] & 0x08) >> 3 != 0);
+ cleanSession = ((data[2] & 0x04) >> 2 !=0);
+ duration = ((data[4] & 0xFF) << 8) + (data[5] & 0xFF);
+
+ // TODO handle this fields
+ protocolName = "MQIsdp";
+ protocolVersion = 3;
+
+ byte[] byteClientId = new byte[data[0] - 6];
+ System.arraycopy(data, 6, byteClientId, 0, byteClientId.length);
+ try {
+ clientId = new String(byteClientId, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the CONNECT message as it should appear on the wire.
+ * (Don't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int length = 6 + clientId.length();
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)0x00;
+ if(will) data[2] |= 0x08;
+ if(cleanSession) data[2] |= 0x04;
+ data[3] = (byte)0x01; // TODO handle this fields
+ data[4] = (byte)((duration >> 8) & 0xFF);
+ data[5] = (byte)(duration & 0xFF);
+ System.arraycopy(clientId.getBytes(), 0, data, 6, clientId.length());
+ return data;
+ }
+
+ public boolean isWill() {
+ return will;
+ }
+
+ public void setWill(boolean will) {
+ this.will = will;
+ }
+
+ public boolean isCleanSession() {
+ return cleanSession;
+ }
+
+ public void setCleanSession(boolean cleanSession) {
+ this.cleanSession = cleanSession;
+ }
+
+ public String getProtocolId() {
+ return protocolId;
+ }
+
+ public void setProtocolId(String protocolId) {
+ this.protocolId = protocolId;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public void setDuration(int duration) {
+ this.duration = duration;
+ }
+
+ public String getProtocolName() {
+ return protocolName;
+ }
+
+ public void setProtocolName(String protocolName) {
+ this.protocolName = protocolName;
+ }
+
+ public int getProtocolVersion() {
+ return protocolVersion;
+ }
+
+ public void setProtocolVersion(int protocolVersion) {
+ this.protocolVersion = protocolVersion;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsDisconnect.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsDisconnect.java
new file mode 100644
index 0000000..f6c0588
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsDisconnect.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts DISCONNECT message.
+ *
+ *
+ */
+public class MqttsDisconnect extends MqttsMessage {
+
+ /**
+ * MqttsDisconnect constructor.Sets the appropriate message type.
+ */
+ public MqttsDisconnect() {
+ msgType = MqttsMessage.DISCONNECT;
+ }
+
+ /**
+ * MqttsDisconnect constructor.Sets the appropriate message type and constructs
+ * a Mqtts DISCONNECT message from a received byte array.
+ * @param data: The buffer that contains the DISCONNECT message.
+ */
+ public MqttsDisconnect(byte[] data) {
+ msgType = MqttsMessage.DISCONNECT;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the DISCONNECT message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsGWInfo.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsGWInfo.java
new file mode 100644
index 0000000..70ed5e2
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsGWInfo.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts GWINFO message.
+ *
+ *
+ */
+public class MqttsGWInfo extends MqttsMessage {
+
+ //Mqtts GWINFO fields
+ private int gwId;
+ private byte[] gwAdd = null;
+
+ /**
+ * MqttsGWInfo constructor.Sets the appropriate message type.
+ */
+ public MqttsGWInfo() {
+ msgType = MqttsMessage.GWINFO;
+ }
+
+ /**
+ * MqttsGWInfo constructor.Sets the appropriate message type and constructs
+ * a Mqtts GWINFO message from a received byte array.
+ * @param data: The buffer that contains the GWINFO message.
+ */
+ public MqttsGWInfo(byte[] data) {
+ msgType = MqttsMessage.GWINFO;
+ gwId = (data[2] & 0xFF);
+ if(data.length > 3)
+ System.arraycopy(data, 3, gwAdd, 0, data.length - 3);
+ }
+
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the GWINFO message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 3 + gwAdd.length;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)gwId;
+ System.arraycopy(gwAdd, 0, data, 3, gwAdd.length);
+ return data;
+ }
+
+ public int getGwId() {
+ return gwId;
+ }
+
+ public void setGwId(int gwId) {
+ this.gwId = gwId;
+ }
+
+ public byte[] getGwAdd() {
+ return gwAdd;
+ }
+
+ public void setGwAdd(byte[] gwAdd) {
+ this.gwAdd = gwAdd;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsMessage.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsMessage.java
new file mode 100644
index 0000000..bd1c3f9
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsMessage.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts message. It is subclassed
+ * to create the appropriate Mqtts Message.
+ *
+ *
+ */
+public abstract class MqttsMessage {
+
+ //Mqtts message types
+ public static final int ADVERTISE = 0x00;
+ public static final int SEARCHGW = 0x01;
+ public static final int GWINFO = 0x02;
+ public static final int CONNECT = 0x04;
+ public static final int CONNACK = 0x05;
+ public static final int WILLTOPICREQ = 0x06;
+ public static final int WILLTOPIC = 0x07;
+ public static final int WILLMSGREQ = 0x08;
+ public static final int WILLMSG = 0x09;
+ public static final int REGISTER = 0x0A;
+ public static final int REGACK = 0x0B;
+ public static final int PUBLISH = 0x0C;
+ public static final int PUBACK = 0x0D;
+ public static final int PUBCOMP = 0x0E;
+ public static final int PUBREC = 0x0F;
+ public static final int PUBREL = 0x10;
+ public static final int SUBSCRIBE = 0x12;
+ public static final int SUBACK = 0x13;
+ public static final int UNSUBSCRIBE = 0x14;
+ public static final int UNSUBACK = 0x15;
+ public static final int PINGREQ = 0x16;
+ public static final int PINGRESP = 0x17;
+ public static final int DISCONNECT = 0x18;
+ public static final int WILLTOPICUPD = 0x1A;
+ public static final int WILLTOPICRESP = 0x1B;
+ public static final int WILLMSGUPD = 0x1C;
+ public static final int WILLMSGRESP = 0x1D;
+
+ //Mqtts message type
+ protected int msgType;
+
+ //Types of topic Ids
+ public final static int NORMAL_TOPIC_ID = 0;
+ public final static int PREDIFINED_TOPIC_ID = 1;
+
+ //Types of topic names
+ public final static int TOPIC_NAME = 0;
+ public final static int SHORT_TOPIC_NAME = 2;
+
+ //Return Code values
+ public final static int RETURN_CODE_ACCEPTED = 0;
+ public final static int RETURN_CODE_REJECTED_CONGESTION = 1;
+ public final static int RETURN_CODE_INVALID_TOPIC_ID = 2;
+
+ /**
+ * MqttsMessage default constructor.
+ */
+ public MqttsMessage() {}
+
+ /**
+ * This method is implemented in subclasses.
+ */
+ public abstract byte[] toBytes ();
+
+
+ public int getMsgType() {
+ return msgType;
+ }
+
+ public void setMsgType(int msgType) {
+ this.msgType = msgType;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingReq.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingReq.java
new file mode 100644
index 0000000..8b5f7f1
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingReq.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PINGREQ message.
+ *
+ *
+ */
+public class MqttsPingReq extends MqttsMessage {
+
+ /**
+ * MqttsPingReq constructor.Sets the appropriate message type.
+ */
+ public MqttsPingReq() {
+ msgType = MqttsMessage.PINGREQ;
+ }
+
+ /**
+ * MqttsPingReq constructor.Sets the appropriate message type and constructs
+ * a Mqtts PINGREQ message from a received byte array.
+ * @param data: The buffer that contains the PINGREQ message.
+ */
+ public MqttsPingReq(byte[] data) {
+ msgType = MqttsMessage.PINGREQ;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PINGREQ message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingResp.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingResp.java
new file mode 100644
index 0000000..80c227e
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPingResp.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PINGRESP message.
+ *
+ *
+ */
+public class MqttsPingResp extends MqttsMessage {
+
+ /**
+ * MqttsPingResp constructor.Sets the appropriate message type.
+ */
+ public MqttsPingResp() {
+ msgType = MqttsMessage.PINGRESP;
+ }
+
+ /**
+ * MqttsPingResp constructor.Sets the appropriate message type and constructs
+ * a Mqtts PINGRESP message from a received byte array.
+ * @param data: The buffer that contains the PINGRESP message.
+ */
+ public MqttsPingResp(byte[] data) {
+ msgType = MqttsMessage.PINGRESP;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PINGRESP message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubComp.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubComp.java
new file mode 100644
index 0000000..3e85d51
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubComp.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PUBCOMP message.
+ *
+ *
+ */
+public class MqttsPubComp extends MqttsMessage {
+
+ //Mqtts PUBCOMP fields
+ private int msgId;
+
+ /**
+ * MqttsPubcomp constructor.Sets the appropriate message type.
+ */
+ public MqttsPubComp() {
+ msgType = MqttsMessage.PUBCOMP;
+ }
+
+ /**
+ * MqttsPubcomp constructor.Sets the appropriate message type and constructs
+ * a Mqtts PUBCOMP message from a received byte array.
+ * @param data: The buffer that contains the PUBCOMP message.
+ */
+ public MqttsPubComp(byte[] data) {
+ msgType = MqttsMessage.PUBCOMP;
+ msgId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PUBCOMP message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 4;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((msgId >> 8) & 0xFF);
+ data[3] = (byte)(msgId & 0xFF);
+ return data;
+
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRec.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRec.java
new file mode 100644
index 0000000..851a9b9
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRec.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PUBREC message.
+ *
+ *
+ */
+public class MqttsPubRec extends MqttsMessage {
+
+ //Mqtts PUBREC fields
+ private int msgId;
+
+ /**
+ * MqttsPubrec constructor.Sets the appropriate message type.
+ */
+ public MqttsPubRec() {
+ msgType = MqttsMessage.PUBREC;
+ }
+
+ /**
+ * MqttsPubrec constructor.Sets the appropriate message type and constructs
+ * a Mqtts PUBREC message from a received byte array.
+ * @param data: The buffer that contains the PUBREC message.
+ */
+ public MqttsPubRec(byte[] data) {
+ msgType = MqttsMessage.PUBREC;
+ msgId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PUBREC message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 4;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((msgId >> 8) & 0xFF);
+ data[3] = (byte)(msgId & 0xFF);
+ return data;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRel.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRel.java
new file mode 100644
index 0000000..8cfa510
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPubRel.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PUBREL message.
+ *
+ *
+ */
+public class MqttsPubRel extends MqttsMessage {
+
+ //Mqtts PUBREL fields
+ private int msgId;
+
+ /**
+ * MqttsPubrel constructor.Sets the appropriate message type.
+ */
+ public MqttsPubRel() {
+ msgType = MqttsMessage.PUBREL;
+ }
+
+ /**
+ * MqttsPubrel constructor.Sets the appropriate message type and constructs
+ * a Mqtts PUBREL message from a received byte array.
+ * @param data: The buffer that contains the PUBREL message.
+ */
+ public MqttsPubRel(byte[] data) {
+ msgType = MqttsMessage.PUBREL;
+ msgId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PUBREL message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 4;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((msgId >> 8) & 0xFF);
+ data[3] = (byte)(msgId & 0xFF);
+ return data;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPuback.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPuback.java
new file mode 100644
index 0000000..1930dcb
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPuback.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts PUBACK message.
+ *
+ *
+ */
+public class MqttsPuback extends MqttsMessage {
+
+ //Mqtts PUBACK fields
+ private int msgId;
+ private int returnCode;
+ private byte[] byteTopicId;
+
+
+ //The form of TopicId maybe either an int or a String.
+ private int topicId = 0;
+ private String shortTopicName = null;
+
+ /**
+ * MqttsPuback constructor.Sets the appropriate message type.
+ */
+ public MqttsPuback() {
+ msgType = MqttsMessage.PUBACK;//check the conversion to bytes
+ }
+
+ /**
+ * MqttsPuback constructor.Sets the appropriate message type and constructs
+ * a Mqtts PUBACK message from a received byte array.
+ * @param data: The buffer that contains the PUBACK message.
+ */
+ public MqttsPuback(byte[] data) {
+ msgType = MqttsMessage.PUBACK;
+ msgId = ((data[4] & 0xFF) << 8) + (data[5] & 0xFF);
+ returnCode = (data[6] & 0xFF);
+ if (returnCode == MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);
+ topicId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PUBACK message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 7;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+
+ byteTopicId = new byte[2];
+ if (this.topicId != 0){
+ byteTopicId[0] = (byte)((topicId >> 8) & 0xFF);
+ byteTopicId[1] = (byte) (topicId & 0xFF);
+ }else if(this.shortTopicName != null)
+ byteTopicId = shortTopicName.getBytes();
+
+ System.arraycopy(byteTopicId, 0, data, 2, byteTopicId.length);
+ data[4] = (byte)((msgId >> 8) & 0xFF);
+ data[5] = (byte) (msgId & 0xFF);
+ data[6] = (byte)returnCode;
+ return data;
+ }
+
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public int getReturnCode() {
+ return returnCode;
+ }
+
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ }
+
+ public int getTopicId() {
+ return topicId;
+ }
+
+ public void setTopicId(int topicId) {
+ this.topicId = topicId;
+ }
+
+ public String getShortTopicName() {
+ return shortTopicName;
+ }
+
+ public void setShortTopicName(String shortTopicName) {
+ this.shortTopicName = shortTopicName;
+ }
+
+ public byte[] getByteTopicId() {
+ return byteTopicId;
+ }
+
+ public void setByteTopicId(byte[] byteTopicId) {
+ this.byteTopicId = byteTopicId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPublish.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPublish.java
new file mode 100644
index 0000000..451bba5
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsPublish.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts PUBLISH message.
+ *
+ *
+ */
+public class MqttsPublish extends MqttsMessage {
+
+ //Mqtts PUBLISH fields
+ private boolean dup;
+ private int qos;
+ private boolean retain;
+ private int topicIdType;
+
+ private byte[] byteTopicId;
+ private int msgId;
+ private byte[] pubData = null;
+
+ //The form of TopicId (or short topic name) that depends on topicIdType.
+ //Maybe either an int or a String.
+ private int topicId = 0;
+ private String shortTopicName = "";
+
+
+ /**
+ * MqttsPublish constructor.Sets the appropriate message type.
+ */
+ public MqttsPublish() {
+ msgType = MqttsMessage.PUBLISH;
+ }
+
+ /**
+ * MqttsPublish constructor.Sets the appropriate message type and constructs
+ * a Mqtts PUBLISH message from a received byte array.
+ * @param data: The buffer that contains the PUBLISH message.
+ */
+ public MqttsPublish(byte[] data) {
+ msgType = MqttsMessage.PUBLISH;
+ dup = ((data[2] & 0x80) >> 7 != 0);
+ qos = (data[2] & 0x60) >> 5;
+ if(qos == 3) qos = -1;
+ retain = ((data[2] & 0x10) >> 4 != 0);
+ topicIdType = (data[2] & 0x03);
+
+ byteTopicId = new byte[2];
+ byteTopicId[0] = data[3];
+ byteTopicId[1] = data[4];
+
+ try {
+ if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME)
+ shortTopicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ else if(topicIdType == MqttsMessage.NORMAL_TOPIC_ID || topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ topicId = ((byteTopicId[0] & 0xFF) << 8) + (byteTopicId[1] & 0xFF);
+ }
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ msgId = ((data[5] & 0xFF) << 8) + (data[6] & 0xFF);
+ int plength = (data[0] & 0xFF) - 7;
+ pubData = new byte[plength];
+ System.arraycopy(data, 7, pubData, 0, plength);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the PUBLISH message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int flags = 0;
+ if(dup) {
+ flags |= 0x80;
+ }
+ if(qos == -1) {
+ flags |= 0x60;
+ } else if(qos == 0) {
+
+ } else if(qos == 1) {
+ flags |= 0x20;
+ } else if(qos == 2) {
+ flags |= 0x40;
+ } else {
+ throw new IllegalArgumentException("Unknown QoS value: " + qos);
+ }
+ if(retain) {
+ flags |= 0x10;
+ }
+ if(topicIdType == MqttsMessage.NORMAL_TOPIC_ID){
+ //do nothing
+ }else if (topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ flags |= 0x01;
+ }else if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ flags |= 0x02;
+ }else {
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ }
+
+ int length = 7 + pubData.length;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+
+ byteTopicId = new byte[2];
+ if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME)
+ byteTopicId = shortTopicName.getBytes();
+ else if(topicIdType == MqttsMessage.NORMAL_TOPIC_ID){
+ byteTopicId[0] = (byte)((topicId >> 8) & 0xFF);
+ byteTopicId[1] = (byte) (topicId & 0xFF);
+ }else
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ System.arraycopy(byteTopicId, 0, data, 3, byteTopicId.length);
+ data[5] = (byte)((msgId >> 8) & 0xFF);
+ data[6] = (byte) (msgId & 0xFF);
+ System.arraycopy(pubData, 0, data, 7, pubData.length);
+ return data;
+ }
+
+ public boolean isDup() {
+ return dup;
+ }
+
+ public void setDup(boolean dup) {
+ this.dup = dup;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+
+ public void setQos(int qos) {
+ this.qos = qos;
+ }
+
+ public boolean isRetain() {
+ return retain;
+ }
+
+ public void setRetain(boolean retain) {
+ this.retain = retain;
+ }
+
+ public int getTopicIdType() {
+ return topicIdType;
+ }
+
+ public void setTopicIdType(int topicIdType) {
+ this.topicIdType = topicIdType;
+ }
+
+ public byte[] getData() {
+ return pubData;
+ }
+
+ public void setData(byte[] data) {
+ this.pubData = data;
+ }
+
+ public byte[] getByteTopicId() {
+ return byteTopicId;
+ }
+
+ public void setByteTopicId(byte[] byteTopicId) {
+ this.byteTopicId = byteTopicId;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public int getTopicId() {
+ return topicId;
+ }
+
+ public void setTopicId(int topicId) {
+ this.topicId = topicId;
+ }
+
+ public String getShortTopicName() {
+ return shortTopicName;
+ }
+
+ public void setShortTopicName(String shortTopicName) {
+ this.shortTopicName = shortTopicName;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegack.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegack.java
new file mode 100644
index 0000000..a634f9d
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegack.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+
+/**
+ * This object represents a Mqtts REGACK message.
+ *
+ *
+ */
+public class MqttsRegack extends MqttsMessage {
+
+ //Mqtts REGACK fields
+ private int msgId;
+ private int returnCode;
+ private int topicId;
+
+ /**
+ * MqttsRegack constructor.Sets the appropriate message type.
+ */
+ public MqttsRegack() {
+ msgType = MqttsMessage.REGACK;
+ }
+
+ /**
+ * MqttsRegack constructor.Sets the appropriate message type and constructs
+ * a Mqtts REGACK message from a received byte array.
+ * @param data: The buffer that contains the REGACK message.
+ */
+ public MqttsRegack(byte[] data) {
+ msgType = MqttsMessage.REGACK;
+ topicId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ msgId = ((data[4] & 0xFF) << 8) + (data[5] & 0xFF);
+ returnCode = (data[6] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the REGACK message as it should appear on the wire.
+ */
+ public byte[] toBytes(){
+ int length = 7;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((topicId >> 8) & 0xFF);
+ data[3] = (byte)(topicId & 0xFF);
+ data[4] = (byte)((msgId >> 8) & 0xFF);
+ data[5] = (byte)(msgId & 0xFF);
+ data[6] = (byte)(returnCode);
+ return data;
+ }
+
+ public int getReturnCode() {
+ return returnCode;
+ }
+
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ }
+
+ public int getTopicId() {
+ return topicId;
+ }
+
+ public void setTopicId(int topicId) {
+ this.topicId = topicId;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegister.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegister.java
new file mode 100644
index 0000000..449ec8e
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsRegister.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts REGISTER message.
+ *
+ *
+ */
+public class MqttsRegister extends MqttsMessage {
+
+ //Mqtts REGISTER fields
+ private int topicId;
+ private int msgId;
+ private String topicName;
+
+ /**
+ * MqttsRegister constructor.Sets the appropriate message type.
+ */
+ public MqttsRegister() {
+ msgType = MqttsMessage.REGISTER;
+ }
+
+ /**
+ * MqttsRegister constructor.Sets the appropriate message type and constructs
+ * a Mqtts REGISTER message from a received byte array.
+ * @param data: The buffer that contains the REGISTER message.
+ */
+ public MqttsRegister(byte[] data) {
+ msgType = MqttsMessage.REGISTER;
+ topicId = 0;//send by the client hlt: ???
+ //hlt 6.3.08
+ topicId= ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ msgId = ((data[4] & 0xFF) << 8) + (data[5] & 0xFF);
+ int tlen = (data[0] & 0xFF) - 6;
+ byte[] byteTopicName = new byte[tlen];
+ System.arraycopy(data, 6, byteTopicName, 0, tlen);
+ try {
+ topicName = new String(byteTopicName, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the REGISTER message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 6 + topicName.length();
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((topicId >> 8) & 0xFF);
+ data[3] = (byte)(topicId & 0xFF);
+ data[4] = (byte)((msgId >> 8) & 0xFF);
+ data[5] = (byte)(msgId & 0xFF);
+ System.arraycopy(topicName.getBytes(), 0, data, 6, topicName.length());
+ return data;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public int getTopicId() {
+ return topicId;
+ }
+
+ public void setTopicId(int topicId) {
+ this.topicId = topicId;
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public void setTopicName(String topicName) {
+ this.topicName = topicName;
+ }
+}
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSearchGW.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSearchGW.java
new file mode 100644
index 0000000..5839472
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSearchGW.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts SEARCHGW message.
+ *
+ *
+ */
+public class MqttsSearchGW extends MqttsMessage{
+
+ //Mqtts SEARCHGW fields
+ private int radius;
+
+ /**
+ * MqttsSearchGW constructor.Sets the appropriate message type.
+ */
+ public MqttsSearchGW() {
+ msgType = MqttsMessage.SEARCHGW;
+ }
+
+ /**
+ * MqttsSearchGW constructor.Sets the appropriate message type and constructs
+ * a Mqtts SEARCHGW message from a received byte array.
+ * @param data: The buffer that contains the SEARCHGW message.
+ */
+ public MqttsSearchGW(byte[] data) {
+ msgType = MqttsMessage.SEARCHGW;
+ radius = (data[2] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the SEARCHGW message as it should appear on the wire.
+ * (Dont't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int length = 3;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)radius;
+ return data;
+ }
+
+ public int getRadius() {
+ return radius;
+ }
+
+ public void setRadius(int radius) {
+ this.radius = radius;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSuback.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSuback.java
new file mode 100644
index 0000000..1649447
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSuback.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts SUBACK message.
+ *
+ *
+ */
+public class MqttsSuback extends MqttsMessage{
+
+ //Mqtts SUBACK fields
+ private int grantedQoS;
+ private int topicIdType;
+ private int msgId = 0;
+ private int returnCode;
+
+ private byte[] byteTopicId;
+
+ //The form of TopicID that depends on TopicIdType.
+ //Maybe either an int or a String.
+ private int topicId = 0;
+ private int predefinedTopicId = 0;
+ private String shortTopicName = "";
+
+ /**
+ * MqttsSuback constructor.Sets the appropriate message type.
+ */
+ public MqttsSuback() {
+ msgType = MqttsMessage.SUBACK;
+ }
+
+ /**
+ * MqttsSuback constructor.Sets the appropriate message type and constructs
+ * a Mqtts SUBACK message from a received byte array.
+ * @param data: The buffer that contains the SUBACK message.
+ * (Don't needed in the GW)
+ */
+ public MqttsSuback(byte[] data){
+ msgType = MqttsMessage.SUBACK;
+ grantedQoS = (data[2] & 0x60) >> 5;
+ if(grantedQoS == 4) grantedQoS = -1;
+ topicIdType = (data[2] & 0x03);
+ byteTopicId = new byte[2];
+ try {
+ if (topicIdType == MqttsMessage.NORMAL_TOPIC_ID){
+ byteTopicId [0] = data[3];
+ byteTopicId [1] = data[4];
+ topicId = ((byteTopicId[0] & 0xFF) << 8) + (byteTopicId[1] & 0xFF);
+ }else if(topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ byteTopicId [0] = data[3];
+ byteTopicId [1] = data[4];
+ predefinedTopicId = ((byteTopicId[0] & 0xFF) << 8) + (byteTopicId[1] & 0xFF);
+ }else if(topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ System.arraycopy(data, 3, byteTopicId, 0, byteTopicId.length);
+ shortTopicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ }else
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ msgId = ((data[5] & 0xFF) << 8) + (data[6] & 0xFF);
+ returnCode = (data[7] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the SUBACK message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int flags = 0;
+ if(grantedQoS == -1) {
+ flags |= 0x60;
+ } else if(grantedQoS == 0) {
+
+ } else if(grantedQoS == 1) {
+ flags |= 0x20;
+ } else if(grantedQoS == 2) {
+ flags |= 0x40;
+ } else {
+ throw new IllegalArgumentException("Unknown QoS value: " + grantedQoS);
+ }
+ byteTopicId = new byte[2];
+ if(topicIdType == MqttsMessage.NORMAL_TOPIC_ID){
+ byteTopicId [0] = (byte)((topicId >> 8) & 0xFF);
+ byteTopicId [1] = (byte) (topicId & 0xFF);
+ }else if (topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ flags |= 0x01;
+ byteTopicId [0] = (byte)((predefinedTopicId >> 8) & 0xFF);
+ byteTopicId [1] = (byte) (predefinedTopicId & 0xFF);
+ }else if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ flags |= 0x02;
+ System.arraycopy(shortTopicName.getBytes(), 0, byteTopicId, 0, byteTopicId.length);
+ }else {
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ }
+
+ int length = 8;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+ data[3] = byteTopicId[0];
+ data[4] = byteTopicId[1];
+ data[5] = (byte)((msgId >> 8) & 0xFF);
+ data[6] = (byte) (msgId & 0xFF);
+ data[7] = (byte)returnCode;
+ return data;
+ }
+
+
+ public int getGrantedQoS() {
+ return grantedQoS;
+ }
+
+ public void setGrantedQoS(int grantedQoS) {
+ this.grantedQoS = grantedQoS;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public byte[] getByteTopicId() {
+ return byteTopicId;
+ }
+
+ public void setByteTopicId(byte[] byteTopicId) {
+ this.byteTopicId = byteTopicId;
+ }
+
+ public int getReturnCode() {
+ return returnCode;
+ }
+
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ }
+
+ public int getTopicId() {
+ return topicId;
+ }
+
+ public void setTopicId(int topicId) {
+ this.topicId = topicId;
+ }
+
+ public int getTopicIdType() {
+ return topicIdType;
+ }
+
+ public void setTopicIdType(int topicIdType) {
+ this.topicIdType = topicIdType;
+ }
+
+ public String getShortTopicName() {
+ return shortTopicName;
+ }
+
+ public void setShortTopicName(String shortTopicName) {
+ this.shortTopicName = shortTopicName;
+ }
+
+ public int getPredefinedTopicId() {
+ return predefinedTopicId;
+ }
+
+ public void setPredefinedTopicId(int predefinedTopicId) {
+ this.predefinedTopicId = predefinedTopicId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSubscribe.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSubscribe.java
new file mode 100644
index 0000000..eb9916c
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsSubscribe.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts SUBSCRIBE message.
+ *
+ *
+ */
+public class MqttsSubscribe extends MqttsMessage {
+
+ //Mqtts SUBSCRIBE message
+ private boolean dup;
+ private int qos;//the requested qos
+ private int topicIdType;
+
+ private int msgId = 0;
+ private byte[] byteTopicId;
+
+ //The form of TopicName(or TopicID) that depends on TopicIdType.
+ //Maybe either an int or a String.
+ private String topicName = "";
+ private int predefinedTopicId = 0;
+ private String shortTopicName = "";
+
+ /**
+ * MqttsSubscribe constructor.Sets the appropriate message type.
+ */
+ public MqttsSubscribe() {
+ msgType = MqttsMessage.SUBSCRIBE;
+ }
+
+ /**
+ * MqttsSubscribe constructor.Sets the appropriate message type and constructs
+ * a Mqtts SUBSCRIBE message from a received byte array.
+ * @param data: The buffer that contains the SUBSCRIBE message.
+ * @throws MqttsException
+ */
+ public MqttsSubscribe(byte[] data) throws MqttsException {
+ msgType = MqttsMessage.SUBSCRIBE;
+ dup = ((data[2] & 0x80) >> 7 != 0);
+ qos = (data[2] & 0x60) >> 5;
+ if(qos == 4) qos = -1;
+ topicIdType = (data[2] & 0x03);
+ msgId = ((data[3] & 0xFF) << 8) + (data[4] & 0xFF);
+
+ int length = (data[0] & 0xFF)-5;
+ byteTopicId = new byte[length];
+
+ try {
+ switch (topicIdType){
+ case MqttsMessage.TOPIC_NAME:
+ System.arraycopy(data, 5, byteTopicId, 0, length);
+ topicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ break;
+
+ case MqttsMessage.PREDIFINED_TOPIC_ID:
+ if(length != 2){
+ throw new MqttsException("Wrong format. Predefined topic id must be 2 bytes long.");
+ }
+ byteTopicId[0] = data[5];
+ byteTopicId[1] = data[6];
+ predefinedTopicId = ((byteTopicId[0] & 0xFF) << 8) + (byteTopicId[1] & 0xFF);
+ break;
+ case MqttsMessage.SHORT_TOPIC_NAME:
+ if(length != 2)
+ throw new MqttsException("Wrong format. Short topic name must be 2 bytes long.");
+ System.arraycopy(data, 5, byteTopicId, 0, byteTopicId.length);
+ shortTopicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ break;
+
+ default:
+ throw new MqttsException("Unknown topic id type: " + topicIdType);
+ }
+
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the SUBSCRIBE message as it should appear on the wire.
+ * (Don't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int flags = 0;
+ if(dup) {
+ flags |= 0x80;
+ }
+ if(qos == -1) {
+ flags |= 0x60; //TODO check if this is right
+ } else if(qos == 0) {
+
+ } else if(qos == 1) {
+ flags |= 0x20;
+ } else if(qos == 2) {
+ flags |= 0x40;
+ } else {
+ throw new IllegalArgumentException("Unknown QoS value: " + qos);
+ }
+ if(topicIdType == MqttsMessage.TOPIC_NAME){
+ byteTopicId = new byte[topicName.length()];
+ System.arraycopy(topicName.getBytes(), 0, byteTopicId, 0, byteTopicId.length);
+ }else if (topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ flags |= 0x01;
+ byteTopicId = new byte[2];
+ byteTopicId [0] = (byte)((predefinedTopicId >> 8) & 0xFF);
+ byteTopicId [1] = (byte) (predefinedTopicId & 0xFF);
+ }else if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ flags |= 0x02;
+ byteTopicId = new byte[2];
+ System.arraycopy(shortTopicName.getBytes(), 0, byteTopicId, 0, byteTopicId.length);
+ }else {
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ }
+
+ int length = 5 + byteTopicId.length;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+ data[3] = (byte)((msgId >> 8) & 0xFF);
+ data[4] = (byte) (msgId & 0xFF);
+ System.arraycopy(byteTopicId, 0, data, 5, byteTopicId.length);
+ return data;
+ }
+
+ public boolean isDup() {
+ return dup;
+ }
+
+ public void setDup(boolean dup) {
+ this.dup = dup;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+
+ public void setQos(int qos) {
+ this.qos = qos;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public void setTopicName(String topicName) {
+ this.topicName = topicName;
+ }
+
+ public int getTopicIdType() {
+ return topicIdType;
+ }
+
+ public void setTopicIdType(int topicIdType) {
+ this.topicIdType = topicIdType;
+ }
+
+ public byte[] getByteTopicId() {
+ return byteTopicId;
+ }
+
+ public void setByteTopicId(byte[] byteTopicId) {
+ this.byteTopicId = byteTopicId;
+ }
+
+ public int getPredefinedTopicId() {
+ return predefinedTopicId;
+ }
+
+ public void setPredefinedTopicId(int predefinedTopicId) {
+ this.predefinedTopicId = predefinedTopicId;
+ }
+
+ public String getShortTopicName() {
+ return shortTopicName;
+ }
+
+ public void setShortTopicName(String shortTopicName) {
+ this.shortTopicName = shortTopicName;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsuback.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsuback.java
new file mode 100644
index 0000000..df495d2
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsuback.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts UNSUBACK message.
+ *
+ *
+ */
+public class MqttsUnsuback extends MqttsMessage{
+
+ //Mqtts UNSUBACK fields
+ private int msgId;
+
+
+ /**
+ * MqttsUnsuback constructor.Sets the appropriate message type.
+ */
+ public MqttsUnsuback() {
+ msgType = MqttsMessage.UNSUBACK;
+ }
+
+ /**
+ * MqttsUnsuback constructor.Sets the appropriate message type and constructs
+ * a Mqtts UNSUBACK message from a received byte array.
+ * @param data: The buffer that contains the UNSUBACK message.
+ * (Don't needed in the GW)
+ */
+ public MqttsUnsuback(byte[] data){
+ msgType = MqttsMessage.UNSUBACK;
+ msgId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the UNSUBACK message as it should appear on the wire.
+ */
+ public byte[] toBytes() {
+ int length = 4;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)((msgId >> 8) & 0xFF);
+ data[3] = (byte)(msgId & 0xFF);
+ return data;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsubscribe.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsubscribe.java
new file mode 100644
index 0000000..d2c32a9
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsUnsubscribe.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts UNSUBSCRIBE message.
+ *
+ *
+ */
+public class MqttsUnsubscribe extends MqttsMessage {
+
+ private boolean dup;
+ private int topicIdType;
+
+ private int msgId = 0;
+ private byte[] byteTopicId;
+
+ //The form of TopicName(or TopicID) that depends on TopicIdType.
+ //Maybe either an int or a String.
+ private String topicName = "";
+ private int predefinedTopicId = 0;
+ private String shortTopicName = "";
+
+ /**
+ * MqttsUnsubscribe constructor.Sets the appropriate message type.
+ */
+ public MqttsUnsubscribe() {
+ msgType = MqttsSubscribe.UNSUBSCRIBE;
+ }
+
+ /**
+ * MqttsUnubscribe constructor.Sets the appropriate message type and constructs
+ * a Mqtts UNSUBSCRIBE message from a received byte array.
+ * @param data: The buffer that contains the UNSUBSCRIBE message.
+ * @throws MqttsException
+ */
+ public MqttsUnsubscribe(byte[] data) throws MqttsException {
+ msgType = MqttsSubscribe.UNSUBSCRIBE;
+ dup = ((data[2] & 0x80) >> 7 != 0);
+ topicIdType = (data[2] & 0x03);
+ msgId = ((data[3] & 0xFF) << 8) + (data[4] & 0xFF);
+
+ int length = (data[0] & 0xFF)-5;
+ byteTopicId = new byte[length];
+
+ try {
+ switch (topicIdType){
+ case MqttsMessage.TOPIC_NAME:
+ System.arraycopy(data, 5, byteTopicId, 0, length);
+ topicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ break;
+
+ case MqttsMessage.PREDIFINED_TOPIC_ID:
+ if(length != 2){
+ throw new MqttsException("Wrong format. Predefined topic id must be 2 bytes long.");
+ }
+ byteTopicId[0] = data[5];
+ byteTopicId[1] = data[6];
+ predefinedTopicId = ((byteTopicId[0] & 0xFF) << 8) + (byteTopicId[1] & 0xFF);
+ break;
+ case MqttsMessage.SHORT_TOPIC_NAME:
+ if(length != 2)
+ throw new MqttsException("Wrong format. Short topic name must be 2 bytes long.");
+ System.arraycopy(data, 5, byteTopicId, 0, byteTopicId.length);
+ shortTopicName = new String(byteTopicId,Utils.STRING_ENCODING);
+ break;
+
+ default:
+ throw new MqttsException("Unknown topic id type: " + topicIdType);
+ }
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the UNSUBSCRIBE message as it should appear on the wire.
+ * (Don't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int flags = 0;
+ if(dup) {
+ flags |= 0x80;
+ }
+ if(topicIdType == MqttsMessage.TOPIC_NAME){
+ byteTopicId = new byte[topicName.length()];
+ System.arraycopy(topicName.getBytes(), 0, byteTopicId, 0, byteTopicId.length);
+ }else if (topicIdType == MqttsMessage.PREDIFINED_TOPIC_ID){
+ flags |= 0x01;
+ byteTopicId = new byte[2];
+ byteTopicId [0] = (byte)((predefinedTopicId >> 8) & 0xFF);
+ byteTopicId [1] = (byte) (predefinedTopicId & 0xFF);
+ }else if (topicIdType == MqttsMessage.SHORT_TOPIC_NAME){
+ flags |= 0x02;
+ byteTopicId = new byte[2];
+ System.arraycopy(shortTopicName.getBytes(), 0, byteTopicId, 0, byteTopicId.length);
+ }else {
+ throw new IllegalArgumentException("Unknown topic id type: " + topicIdType);
+ }
+
+ int length = 5 + byteTopicId.length;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+ data[3] = (byte)((msgId >> 8) & 0xFF);
+ data[4] = (byte) (msgId & 0xFF);
+ System.arraycopy(byteTopicId, 0, data, 5, byteTopicId.length);
+ return data;
+ }
+
+
+ public boolean isDup() {
+ return dup;
+ }
+
+ public void setDup(boolean dup) {
+ this.dup = dup;
+ }
+
+ public int getTopicIdType() {
+ return topicIdType;
+ }
+
+ public void setTopicIdType(int topicIdType) {
+ this.topicIdType = topicIdType;
+ }
+
+ public int getMsgId() {
+ return msgId;
+ }
+
+ public void setMsgId(int msgId) {
+ this.msgId = msgId;
+ }
+
+ public byte[] getByteTopicId() {
+ return byteTopicId;
+ }
+
+ public void setByteTopicId(byte[] byteTopicId) {
+ this.byteTopicId = byteTopicId;
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public void setTopicName(String topicName) {
+ this.topicName = topicName;
+ }
+
+ public int getPredefinedTopicId() {
+ return predefinedTopicId;
+ }
+
+ public void setPredefinedTopicId(int predefineTopicId) {
+ this.predefinedTopicId = predefineTopicId;
+ }
+
+ public String getShortTopicName() {
+ return shortTopicName;
+ }
+
+ public void setShortTopicName(String shortTopicName) {
+ this.shortTopicName = shortTopicName;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsg.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsg.java
new file mode 100644
index 0000000..33067b2
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsg.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+
+/**
+ * This object represents a Mqtts WILLMSG message.
+ *
+ *
+ */
+public class MqttsWillMsg extends MqttsMessage {
+
+ //Mqtts WILLMSG fields
+ private String willMsg;
+
+ /**
+ * MqttsWillMsg constructor.Sets the appropriate message type.
+ */
+ public MqttsWillMsg() {
+ msgType = MqttsMessage.WILLMSG;
+ }
+
+ /**
+ * MqttsWillMsg constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLMSG message from a received byte array.
+ * @param data: The buffer that contains the WILLMSG message.
+ */
+ public MqttsWillMsg(byte[] data) {
+ msgType = MqttsMessage.WILLMSG;
+ try {
+ willMsg = new String(data, 2, data[0] - 2, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLMSG message as it should appear on the wire.
+ * (Don't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int length = willMsg.length() + 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ System.arraycopy(willMsg.getBytes(), 0, data, 2, willMsg.length());
+ return data;
+ }
+
+ public String getWillMsg() {
+ return willMsg;
+ }
+
+ public void setWillMsg(String willMsg) {
+ this.willMsg = willMsg;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgReq.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgReq.java
new file mode 100644
index 0000000..e050a6a
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgReq.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts WILLMSGREQ message.
+ *
+ *
+ */
+public class MqttsWillMsgReq extends MqttsMessage{
+
+ /**
+ * MqttsWillMsgReq constructor.Sets the appropriate message type.
+ */
+ public MqttsWillMsgReq() {
+ msgType = MqttsMessage.WILLMSGREQ;
+ }
+
+ /**
+ * MqttsWillMsgReq constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLMSGREQ message from a received byte array.
+ * @param data: The buffer that contains the WILLMSGREQ message.
+ */
+ public MqttsWillMsgReq(byte[] data){
+ msgType = MqttsMessage.WILLMSGREQ;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLMSGREQ message as it should appear on the wire.
+ */
+ public byte [] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgResp.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgResp.java
new file mode 100644
index 0000000..256ad43
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgResp.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts WILLMSGRESP message.
+ *
+ *
+ */
+public class MqttsWillMsgResp extends MqttsMessage{
+
+ /**
+ * MqttsWillMsgResp constructor.Sets the appropriate message type.
+ */
+ public MqttsWillMsgResp() {
+ msgType = MqttsMessage.WILLMSGRESP;
+ }
+
+ /**
+ * MqttsWillMsgResp constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLMSGRESP message from a received byte array.
+ * @param data: The buffer that contains the WILLMSGRESP message.
+ */
+ public MqttsWillMsgResp(byte[] data){
+ msgType = MqttsMessage.WILLMSGRESP;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLMSGRESP message as it should appear on the wire.
+ */
+ public byte [] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgUpd.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgUpd.java
new file mode 100644
index 0000000..029ce76
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillMsgUpd.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+
+/**
+ * This object represents a Mqtts WILLMSGRUPD message.
+ *
+ *
+ */
+public class MqttsWillMsgUpd extends MqttsMessage {
+
+ //Mqtts WILLMSGUPD message
+ private String willMsg;
+
+ /**
+ * MqttsWillMsgUpd constructor.Sets the appropriate message type.
+ */
+ public MqttsWillMsgUpd() {
+ msgType = MqttsMessage.WILLMSGUPD;
+ }
+
+ /**
+ * MqttsWillMsgUpd constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLMSGRUPD message from a received byte array.
+ * @param data: The buffer that contains the WILLMSGUPD message.
+ */
+ public MqttsWillMsgUpd(byte[] data) {
+ msgType = MqttsMessage.WILLMSGUPD;
+ try {
+ willMsg = new String(data, 2, data[0] - 2, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLMSGRUPD message as it should appear on the wire.
+ */
+ public byte[] toBytes(){
+ int length = 2 + willMsg.length();
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ System.arraycopy(willMsg.getBytes(), 0, data, 2, willMsg.length());
+ return data;
+ }
+
+ public String getWillMsg() {
+ return willMsg;
+ }
+
+ public void setWillMsg(String willMsg) {
+ this.willMsg = willMsg;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopic.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopic.java
new file mode 100644
index 0000000..5417864
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopic.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+/**
+ * This object represents a Mqtts WILLTOPIC message.
+ *
+ *
+ */
+public class MqttsWillTopic extends MqttsMessage {
+
+ //Mqtts WILLTOPIC fields
+ private int qos;
+ private boolean retain = false;
+ private String willTopic ="";
+
+ /**
+ * MqttsWillTopic constructor.Sets the appropriate message type.
+ */
+ public MqttsWillTopic() {
+ msgType = MqttsMessage.WILLTOPIC;
+ }
+
+ /**
+ * MqttsWillTopic constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLTOPIC message from a received byte array.
+ * @param data: The buffer that contains the WILLTOPIC message.
+ */
+ public MqttsWillTopic(byte[] data) {
+ msgType = MqttsMessage.WILLTOPIC;
+ if (data.length > 3){ //non empty WILLTOPIC message
+ qos = (data[2] & 0x60) >> 5;
+ retain = ((data[2] & 0x10) >> 4 != 0);
+ try {
+ willTopic = new String(data, 3, data[0] - 3, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLTOPIC message as it should appear on the wire.
+ * (Don't needed in the GW)
+ */
+ public byte[] toBytes(){
+ int length = 3 + willTopic.length();
+ byte[] data = new byte[length];
+ int flags = 0;
+ if(qos == -1) {
+ flags |= 0x60;
+ } else if(qos == 0) {
+
+ } else if(qos == 1) {
+ flags |= 0x20;
+ } else if(qos == 2) {
+ flags |= 0x40;
+ } else {
+ throw new IllegalArgumentException("Unknown QoS value: " + qos);
+ }
+ if(retain) {
+ flags |= 0x10;
+ }
+
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+ System.arraycopy(willTopic.getBytes(), 0, data, 3, willTopic.length());
+ return data;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+ public void setQos(int qoS) {
+ this.qos = qoS;
+ }
+ public boolean isRetain() {
+ return retain;
+ }
+ public void setRetain(boolean retain) {
+ this.retain = retain;
+ }
+ public String getWillTopic() {
+ return willTopic;
+ }
+ public void setWillTopic(String willTopic) {
+ this.willTopic = willTopic;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicReq.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicReq.java
new file mode 100644
index 0000000..c666ded
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicReq.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts WILLTOPICREQ message.
+ *
+ */
+public class MqttsWillTopicReq extends MqttsMessage{
+
+ /**
+ * MqttsWillTopicReq constructor.Sets the appropriate message type.
+ */
+ public MqttsWillTopicReq() {
+ msgType = MqttsMessage.WILLTOPICREQ;
+ }
+
+ /**
+ * MqttsWillTopicReq constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLTOPICREQ message from a received byte array.
+ * @param data: The buffer that contains the WILLTOPICREQ message.
+ */
+ public MqttsWillTopicReq(byte[] data){
+ msgType = MqttsMessage.WILLTOPICREQ;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLTOPICREQ message as it should appear on the wire.
+ */
+ public byte [] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicResp.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicResp.java
new file mode 100644
index 0000000..1adcd14
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicResp.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+/**
+ * This object represents a Mqtts WILLTOPICRESP message.
+ *
+ *
+ */
+public class MqttsWillTopicResp extends MqttsMessage{
+
+ /**
+ * MqttsWillTopicResp constructor.Sets the appropriate message type.
+ */
+ public MqttsWillTopicResp() {
+ msgType = MqttsMessage.WILLTOPICRESP;
+ }
+
+ /**
+ * MqttsWillTopicResp constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLTOPICRESP message from a received byte array.
+ * @param data: The buffer that contains the WILLTOPICRESP message.
+ */
+ public MqttsWillTopicResp(byte[] data){
+ msgType = MqttsMessage.WILLTOPICRESP;
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLTOPICRESP message as it should appear on the wire.
+ */
+ public byte [] toBytes() {
+ int length = 2;
+ byte[] data = new byte[length];
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicUpd.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicUpd.java
new file mode 100644
index 0000000..c9c94f4
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/messages/mqttsn/MqttsWillTopicUpd.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.messages.mqttsn;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.paho.mqttsn.udpclient.utils.Utils;
+
+
+/**
+ * This object represents a Mqtts WILLTOPICUPD message.
+ *
+ *
+ */
+public class MqttsWillTopicUpd extends MqttsMessage {
+
+ //Mqtts WILLTOPICUPD fields
+ private int qos;
+ private boolean retain;
+ private String willTopic;
+
+ /**
+ * MqttsWillTopicUpd constructor.Sets the appropriate message type.
+ */
+ public MqttsWillTopicUpd() {
+ msgType = MqttsMessage.WILLTOPICUPD;
+ }
+
+ /**
+ * MqttsWillTopicUpd constructor.Sets the appropriate message type and constructs
+ * a Mqtts WILLTOPICUPD message from a received byte array.
+ * @param data: The buffer that contains the WILLTOPICUPD message.
+ */
+ public MqttsWillTopicUpd(byte[] data) {
+ msgType = MqttsMessage.WILLTOPICUPD;
+ qos = (data[2] & 0x60) >> 5;
+ retain = ((data[2] & 0x10) >> 4 !=0);
+ try {
+ willTopic = new String(data, 3, data[0] - 3, Utils.STRING_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to convert this message to a byte array for transmission.
+ * @return A byte array containing the WILLTOPICUPD message as it should appear on the wire.
+ */
+ public byte[] toBytes(){
+ int length = 3 + willTopic.length();
+ byte[] data = new byte[length];
+ int flags = 0;
+ if(qos == -1) {
+ flags |= 0x60;
+ } else if(qos == 0) {
+
+ } else if(qos == 1) {
+ flags |= 0x20;
+ } else if(qos == 2) {
+ flags |= 0x40;
+ } else {
+ throw new IllegalArgumentException("Unknown QoS value: " + qos);
+ }
+ if(retain) {
+ flags |= 0x10;
+ }
+
+ data[0] = (byte)length;
+ data[1] = (byte)msgType;
+ data[2] = (byte)flags;
+ System.arraycopy(willTopic.getBytes(), 0, data, 3, willTopic.length());
+ return data;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+ public void setQos(int qoS) {
+ this.qos = qoS;
+ }
+ public boolean isRetain() {
+ return retain;
+ }
+ public void setRetain(boolean retain) {
+ this.retain = retain;
+ }
+ public String getWillTopic() {
+ return willTopic;
+ }
+ public void setWillTopic(String willTopic) {
+ this.willTopic = willTopic;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/timer/TimerService.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/timer/TimerService.java
new file mode 100644
index 0000000..c877dc9
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/timer/TimerService.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.timer;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.Vector;
+
+import org.eclipse.paho.mqttsn.udpclient.messages.Message;
+import org.eclipse.paho.mqttsn.udpclient.messages.control.ControlMessage;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientLogger;
+import org.eclipse.paho.mqttsn.udpclient.utils.MsgQueue;
+
+
+
+@SuppressWarnings({"static-access"})
+public class TimerService {
+
+ private static Timer timer=null;
+ private MsgQueue queue;
+ private Vector<TimeoutTimerTask> timeoutTasks;
+
+ /**
+ * Constructor.
+ */
+ public TimerService(MsgQueue queue) {
+ if(timer==null) {
+ timer=new Timer();
+ }
+ this.queue = queue;
+ timeoutTasks = new Vector<TimeoutTimerTask>();
+ }
+
+
+ public void register(int type, int timeout) {
+ ClientLogger.log(ClientLogger.INFO, "Timer "+ type +" started, duration= "+ timeout);
+ long delay = timeout * 1000;
+ long period = timeout * 1000;
+
+ for(int i = 0 ; i<timeoutTasks.size(); i++) {
+ TimeoutTimerTask timeoutTimerTask = (TimeoutTimerTask) timeoutTasks.get(i);
+ if (timeoutTimerTask.getType() == type){
+ return;
+ }
+ }
+
+ TimeoutTimerTask timeoutTimerTask = new TimeoutTimerTask(type);
+
+ //put this timeoutTimerTask in a list
+ timeoutTasks.add(timeoutTimerTask);
+
+ //schedule for future executions
+ timer.scheduleAtFixedRate(timeoutTimerTask, delay, period);
+ }
+
+
+
+ public void unregister(int type) {
+ ClientLogger.log(ClientLogger.INFO, "Timer "+type+" stopped");
+ for(int i = 0 ; i<timeoutTasks.size(); i++) {
+ TimeoutTimerTask timeout = (TimeoutTimerTask) timeoutTasks.get(i);
+ if (timeout.getType() == type){
+ timeoutTasks.remove(i);
+ timeout.cancel();
+ break;
+ }
+ }
+ }
+
+ public void unregisterAll(){
+ //ClientLogger.log(ClientLogger.INFO, "All timers stopped");
+ for(int i = timeoutTasks.size()-1; i >= 0; i--) {
+ TimeoutTimerTask timeout = (TimeoutTimerTask) timeoutTasks.get(i);
+ timeoutTasks.remove(i);
+ timeout.cancel();
+ }
+ }
+
+ public void terminate() {
+ this.unregisterAll();
+ this.timer.cancel();
+ }
+
+
+ public class TimeoutTimerTask extends TimerTask {
+ int type;
+
+ /**
+ * Constructor.
+ *
+ */
+ public TimeoutTimerTask(int type) {
+ this.type = type;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.TimerTask#run()
+ */
+ public void run(){
+ //create new control message
+ ControlMessage controlMsg = new ControlMessage();
+ controlMsg.setMsgType(type);
+
+ //create an "internal" message
+ Message msg = new Message();
+ msg.setType(Message.CONTROL_MSG);
+ msg.setControlMessage(controlMsg);
+
+ //put this message to the Dispatcher's queue
+ queue.addFirst(msg);
+ }
+
+ public int getType() {
+ return type;
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/udp/UDPInterface.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/udp/UDPInterface.java
new file mode 100644
index 0000000..e4a7f56
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/udp/UDPInterface.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.udp;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.udpclient.messages.Message;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsAdvertise;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsConnack;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsDisconnect;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsGWInfo;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsMessage;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPingReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPingResp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubComp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubRec;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPubRel;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsPublish;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsRegack;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsRegister;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsSearchGW;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsSuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsUnsuback;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillMsgReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillMsgResp;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillTopicReq;
+import org.eclipse.paho.mqttsn.udpclient.messages.mqttsn.MqttsWillTopicResp;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientLogger;
+import org.eclipse.paho.mqttsn.udpclient.utils.ClientParameters;
+import org.eclipse.paho.mqttsn.udpclient.utils.MsgQueue;
+
+/**
+ * This class implements a UDP interface
+ */
+public class UDPInterface implements Runnable {
+
+ private final static int MAXUDPSIZE=65536;
+ private final static int MINUDPSIZE=16; // assumed to be a "sane" value...
+ public final static boolean ENCAPS=false; //use forwarder encapsulation or not
+
+ private DatagramSocket udpSocket;
+ private volatile boolean running;
+ private Thread readThread;
+ private MsgQueue queue;
+ private ClientParameters clientParms;
+ private byte[] recData;
+
+
+ public void initialize(MsgQueue queue, ClientParameters clientParms) throws MqttsException {
+ try {
+ //create the udp socket
+ udpSocket = new DatagramSocket();
+
+ //get the queue
+ this.queue = queue;
+ this.clientParms = clientParms;
+ // set the buffer space.
+ if(this.clientParms.getMaxMqttsLength() > MAXUDPSIZE) {
+ throw new IllegalArgumentException("UDP only supports packet sizes up to 64KByte!");
+ }
+ if(this.clientParms.getMaxMqttsLength() < MINUDPSIZE) {
+ throw new IllegalArgumentException("Maximum packet size should be larger than "+MINUDPSIZE);
+ }
+ recData = new byte[this.clientParms.getMaxMqttsLength()];
+
+ //create thread for reading
+ this.readThread = new Thread (this, "UDPInterface");
+ this.running = true;
+ this.readThread.start();
+ } catch (Exception e) {
+ throw new MqttsException ("UDPInterface - Error initializing :" +e);
+ }
+ }
+
+
+ public int getUdpPort() {
+ return udpSocket.getLocalPort();
+ }
+
+ public void readMsg() {
+ DatagramPacket packet = new DatagramPacket(recData,0, recData.length);
+ try {
+ packet.setLength(recData.length);
+ udpSocket.receive(packet);
+
+ //old encapsulation
+// byte[] data = new byte[packet.getLength()];
+// System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());
+// byte[] clAddr = new byte[data[1]];
+// System.arraycopy(data, 2, clAddr, 0, clAddr.length);
+// byte[] mqttsData = new byte[data.length - clAddr.length - 2];
+// System.arraycopy(data, clAddr.length + 2, mqttsData, 0, mqttsData.length);
+
+ //no encapsulation
+// byte[] mqttsData = new byte[packet.getLength()];
+// System.arraycopy(packet.getData(), packet.getOffset(), mqttsData, 0, packet.getLength());
+
+ byte[] mqttsData = null;
+ if (ENCAPS) {
+ //new encapsulation spec v1.2
+ byte[] data = new byte[packet.getLength()];
+ System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());
+ mqttsData = new byte[data.length - data[0]]; //data[0] contains length of encapsulation
+ System.arraycopy(data, data[0], mqttsData, 0, mqttsData.length);
+ } else {
+ mqttsData = new byte[packet.getLength()];
+ System.arraycopy(packet.getData(), packet.getOffset(), mqttsData, 0, packet.getLength());
+ }
+
+ ClientLogger.log(ClientLogger.INFO, "UDPInterface - Packet received, decoding ...");
+ decodeMsg(mqttsData);
+ }catch (IOException ex){
+ if(this.running) {
+ ex.printStackTrace();
+ ClientLogger.log(ClientLogger.ERROR, "UDPInterface - An I/O error occurred while reading from the socket.");
+ }
+ }
+ }
+
+
+ public void decodeMsg(byte[] data) {
+ MqttsMessage mqttsMsg = null;
+
+ //do some checks for the received packet
+ if(data == null) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - The received data packet is null. The packet cannot be processed.");
+ return;
+ }
+
+ if(data.length < clientParms.getMinMqttsLength()) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts message. The received data packet is too short (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+
+ if(data.length > clientParms.getMaxMqttsLength()){
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts message. The received data packet is too long (length = "+data.length +"). The packet cannot be processed.");
+ return;
+
+ }
+
+ if((data[0] & 0xFF) < clientParms.getMinMqttsLength()) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts message. Field \"Length\" (" + (data[0] & 0xFF) + ") in the received data packet is less than "+clientParms.getMinMqttsLength()+" . The packet cannot be processed.");
+ return;
+ }
+
+ if((data[0] & 0xFF) != data.length) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts message. Field \"Length\" in the received data packet does not match the actual length of the packet. The packet cannot be processed. " + data[0] + ", " + data.length);
+ return;
+ }
+
+
+ int msgType = (data[1] & 0xFF);
+ switch (msgType) {
+ case MqttsMessage.ADVERTISE:
+ if(data.length != 5) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts ADVERTISE message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsAdvertise(data);
+ break;
+
+ case MqttsMessage.SEARCHGW:
+ if(data.length != 3) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts SEARCHGW message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsSearchGW(data);
+ break;
+
+ case MqttsMessage.GWINFO:
+ mqttsMsg = new MqttsGWInfo(data);
+ break;
+
+ case MqttsMessage.CONNECT:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a CONNECT was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.CONNACK:
+ mqttsMsg = new MqttsConnack(data);
+ ClientLogger.log(ClientLogger.INFO, "UDPInterface - CONNACK received");
+ break;
+
+ case MqttsMessage.WILLTOPICREQ:
+ mqttsMsg = new MqttsWillTopicReq(data);
+ break;
+
+ case MqttsMessage.WILLTOPIC:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a WILLTOPIC was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.WILLMSGREQ:
+ mqttsMsg = new MqttsWillMsgReq(data);
+ break;
+
+ case MqttsMessage.WILLMSG:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a WILLMSG was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.REGISTER:
+ if(data.length < 7) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts REGISTER message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsRegister(data);
+ break;
+
+ case MqttsMessage.REGACK:
+ if(data.length != 7) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts REGACK message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsRegack(data);
+ break;
+
+ case MqttsMessage.PUBLISH:
+ if(data.length < 8) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts PUBLISH message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsPublish(data);
+ break;
+
+ case MqttsMessage.PUBACK:
+ if(data.length != 7) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts PUBACK message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsPuback(data);
+ break;
+
+ case MqttsMessage.PUBCOMP:
+ if(data.length != 4) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts PUBCOMP message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsPubComp(data);
+ break;
+
+ case MqttsMessage.PUBREC:
+ if(data.length != 4) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts PUBREC message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsPubRec(data);
+ break;
+
+ case MqttsMessage.PUBREL:
+ if(data.length != 4) {
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Not a valid Mqtts PUBREL message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+ return;
+ }
+ mqttsMsg = new MqttsPubRel(data);
+ break;
+
+ case MqttsMessage.SUBSCRIBE:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a SUBSCRIBE was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.SUBACK:
+ mqttsMsg = new MqttsSuback(data);
+ break;
+
+ case MqttsMessage.UNSUBSCRIBE :
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a UNSUBSCRIBE was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.UNSUBACK:
+ mqttsMsg = new MqttsUnsuback(data);
+ break;
+
+ case MqttsMessage.PINGREQ:
+ mqttsMsg = new MqttsPingReq(data);
+ break;
+
+ case MqttsMessage.PINGRESP:
+ mqttsMsg = new MqttsPingResp(data);
+ break;
+
+ case MqttsMessage.DISCONNECT :
+ mqttsMsg = new MqttsDisconnect(data);
+ break;
+
+ case MqttsMessage.WILLTOPICUPD:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a WILLTOPICUPD was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.WILLTOPICRESP:
+ mqttsMsg = new MqttsWillTopicResp(data);
+ break;
+
+ case MqttsMessage.WILLMSGUPD:
+ //we should never receive such a message from the gateway
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Strange ... a WILLMSGUPD was received, something must be wrong here ...");
+ break;
+
+ case MqttsMessage.WILLMSGRESP:
+ mqttsMsg = new MqttsWillMsgResp(data);
+ break;
+
+ default:
+ ClientLogger.log(ClientLogger.WARN, "UDPInterface - Mqtts message of unknown type \"" + msgType+"\" received.");
+ return;
+ }
+
+ //put the message to the queue
+ Message msg = new Message();
+ msg.setType(Message.MQTTS_MSG);
+ msg.setMqttsMessage(mqttsMsg);
+ this.queue.addLast(msg);
+ ClientLogger.log(ClientLogger.INFO, "UDPInterface - Mqtts message \"" + msgType+"\" put in queue.");
+ }
+
+ public void sendMsg(MqttsMessage msg) {
+ try {
+
+//old encapsulation spec v1.1
+// //cll: temp modification for testing reasons
+// //byte[] ipAddr = InetAddress.getLocalHost().getAddress();
+// byte[] ipAddr = new byte[] {127,0,0,1};
+// byte[] port = new byte[2];
+//
+// int udpPort = this.udpSocket.getLocalPort();
+// port[0] = (byte)((udpPort >> 8) & 0xFF);
+// port[1] = (byte) ( udpPort & 0xFF);
+//
+// byte[] clientAddr = new byte [ipAddr.length + port.length];
+// System.arraycopy(ipAddr, 0, clientAddr, 0, ipAddr.length);
+// System.arraycopy(port, 0, clientAddr, ipAddr.length, port.length);
+//
+// byte[] wireMsg = msg.toBytes();
+// byte[] data = new byte[wireMsg.length + clientAddr.length + 2];
+// data[0] = (byte)0x00;
+// data[1] = (byte)clientAddr.length;
+// System.arraycopy(clientAddr, 0, data, 2, clientAddr.length);
+// System.arraycopy(wireMsg, 0, data, clientAddr.length + 2, wireMsg.length);
+// DatagramPacket packet = new DatagramPacket(data, data.length, clientParms.getGatewayAddress(), clientParms.getGatewayPort());
+//end old encapsulation
+
+ if (ENCAPS) { //new encapsulation acc. spec 1.2
+ byte[] ipAddr = InetAddress.getLocalHost().getAddress();
+ //byte[] ipAddr = new byte[] {127,0,0,1};
+ byte[] port = new byte[2];
+ int udpPort = this.udpSocket.getLocalPort();
+ port[0] = (byte)((udpPort >> 8) & 0xFF);
+ port[1] = (byte) ( udpPort & 0xFF);
+ byte[] wirelessNodeId = new byte [ipAddr.length + port.length];
+ System.arraycopy(ipAddr, 0, wirelessNodeId, 0, ipAddr.length);
+ System.arraycopy(port, 0, wirelessNodeId, ipAddr.length, port.length);
+
+ byte[] wireMsg = msg.toBytes();
+ byte[] data = new byte[wireMsg.length + wirelessNodeId.length + 3];
+ data[0] = (byte)(wirelessNodeId.length+3);
+ data[1] = (byte)0xFE;
+ data[3] = 0x00;
+ System.arraycopy(wirelessNodeId, 0, data, 3, wirelessNodeId.length);
+ System.arraycopy(wireMsg, 0, data, wirelessNodeId.length + 3, wireMsg.length);
+ DatagramPacket packet = new DatagramPacket(data, data.length, clientParms.getGatewayAddress(), clientParms.getGatewayPort());
+ udpSocket.send(packet);
+ } else { //no encapsulation
+ byte[] wireMsg = msg.toBytes();
+ DatagramPacket packet = new DatagramPacket(wireMsg, wireMsg.length, clientParms.getGatewayAddress(), clientParms.getGatewayPort());
+ udpSocket.send(packet);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ ClientLogger.log(ClientLogger.ERROR, "UDPInterface - Error while writing on the UDP socket.");
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ while (running) {
+ readMsg();
+ }
+ }
+
+ public void terminate() {
+ this.running=false;
+ // close socket.
+ this.udpSocket.close();
+ try {
+ this.readThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientLogger.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientLogger.java
new file mode 100644
index 0000000..6fa2704
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientLogger.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.utils;
+
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.paho.mqttsn.udpclient.exceptions.MqttsException;
+
+public class ClientLogger {
+
+ public final static int ALL = 0;
+ public final static int INFO = 1;
+ public final static int WARN = 2;
+ public final static int ERROR = 3;
+
+ private static int LOG_LEVEL = WARN;
+
+
+ public static void all(String msg) {
+ DateFormat dFormat = new SimpleDateFormat("dd.MM.yy HH:mm:ss.SSS");
+ System.out.println(dFormat.format(new Date())+ " INFO: " + msg);
+ if(printWriter != null){
+ printWriter.println(dFormat.format(new Date())+ " INFO: " + msg);
+ printWriter.flush();
+ }
+ }
+
+ public static void info(String msg) {
+ DateFormat dFormat = new SimpleDateFormat("dd.MM.yy HH:mm:ss.SSS");
+ //System.out.println(dFormat.format(new Date())+ " INFO: " + msg);
+ if(printWriter != null){
+ printWriter.println(dFormat.format(new Date())+ " INFO: " + msg);
+ printWriter.flush();
+ }
+ }
+
+ public static void warn(String msg) {
+ DateFormat dFormat= new SimpleDateFormat("dd.MM.yy HH:mm:ss.SSS");
+ System.err.println(dFormat.format(new Date())+ " WARN: "+ msg);
+ if(printWriter != null){
+ printWriter.println(dFormat.format(new Date())+ " WARN: "+ msg);
+ printWriter.flush();
+ }
+ }
+
+ public static void error(String msg) {
+ DateFormat dFormat= new SimpleDateFormat("dd.MM.yy HH:mm:ss.SSS");
+ System.err.println(dFormat.format(new Date())+ " ERROR: " + msg);
+ if(printWriter != null){
+ printWriter.println(dFormat.format(new Date())+ " ERROR: " + msg);
+ printWriter.flush();
+ }
+ }
+
+
+ public static void log(int logLevel, String msg) {
+ if(logLevel >= LOG_LEVEL) {
+ switch (logLevel){
+ case INFO:
+ if (LOG_LEVEL == ALL) all(msg);
+ else info(msg);
+ break;
+ case WARN:
+ warn(msg);
+ break;
+ case ERROR:
+ error(msg);
+ break;
+ default:
+ }
+ }
+ }
+
+
+ public static void setLogLevel(int logLevel) {
+ LOG_LEVEL = logLevel;
+ }
+
+
+ private static FileWriter fileWriter;
+ private static PrintWriter printWriter;
+
+ public static void setLogFile(String file) throws MqttsException {
+ //DateFormat dFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
+ try {
+ fileWriter = new FileWriter(file);
+ printWriter = new PrintWriter(fileWriter);
+ printWriter.println();
+ } catch(IOException e) {
+ e.printStackTrace();
+ throw new MqttsException (e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientParameters.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientParameters.java
new file mode 100644
index 0000000..b2cce53
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/ClientParameters.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.utils;
+
+import java.net.InetAddress;
+
+
+public class ClientParameters {
+
+ //the address of the gateway
+ private InetAddress gatewayAddress;
+
+ //the UDP port of the gateway
+ private int gatewayPort;
+
+ //the broadcast radius of the SEARCHGW message
+ //private int searchGWBroadcastRadius = 1;
+
+ //the maximum length of the Mqtts message
+ private int maxMqttsLength;
+
+ //the minimum length of the Mqtts message
+ private int minMqttsLength;
+
+ //the keep alive period (in seconds)
+ private int keepAlivePeriod;
+
+ //maximum retries of sending a message
+ private int maxRetries;
+
+ //maximum time (in seconds) waiting for a message
+ private int waitingTime;
+
+
+
+
+
+
+ public InetAddress getGatewayAddress() {
+ return gatewayAddress;
+ }
+
+ public void setGatewayAddress(InetAddress gatewayAddress) {
+ this.gatewayAddress = gatewayAddress;
+ }
+
+ public int getGatewayPort() {
+ return gatewayPort;
+ }
+
+ public void setGatewayPort(int gatewayPort) {
+ this.gatewayPort = gatewayPort;
+ }
+
+// public int getSearchGWBroadcastRadius() {
+// return searchGWBroadcastRadius;
+// }
+//
+// public void setSearchGWBroadcastRadius(int searchGWBroadcastRadius) {
+// this.searchGWBroadcastRadius = searchGWBroadcastRadius;
+// }
+
+ public int getMaxMqttsLength() {
+ return maxMqttsLength;
+ }
+
+ public void setMaxMqttsLength(int maxMqttsLength) {
+ this.maxMqttsLength = maxMqttsLength;
+ }
+
+ public int getMinMqttsLength() {
+ return minMqttsLength;
+ }
+
+ public void setMinMqttsLength(int minMqttsLength) {
+ this.minMqttsLength = minMqttsLength;
+ }
+
+ public int getKeepAlivePeriod() {
+ return keepAlivePeriod;
+ }
+
+ public void setKeepAlivePeriod(int keepAlivePeriod) {
+ this.keepAlivePeriod = keepAlivePeriod;
+ }
+
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ public void setMaxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ public int getWaitingTime() {
+ return waitingTime;
+ }
+
+ public void setWaitingTime(int waitingTime) {
+ this.waitingTime = waitingTime;
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/MsgQueue.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/MsgQueue.java
new file mode 100644
index 0000000..8e82f92
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/MsgQueue.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.utils;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+public class MsgQueue {
+
+ private LinkedList<Object> queue;
+ private volatile boolean isClosed;
+
+ public MsgQueue() {
+ queue = new LinkedList<Object>();
+ isClosed = false;
+ }
+
+ public void close() {
+ synchronized (queue) {
+ isClosed = true;
+ queue.notifyAll();
+ }
+ }
+
+ /**
+ * @param o
+ */
+ public void addLast(Object o) {
+ synchronized (queue) {
+ if(isClosed) {
+ throw new IllegalStateException("Queue is closed.");
+ }
+ queue.add(o);
+ queue.notify();
+ }
+ }
+
+ /**
+ * @param o
+ */
+ public void addFirst(Object o) {
+ synchronized (queue) {
+ if(isClosed) {
+ throw new IllegalStateException("Queue is closed.");
+ }
+ queue.addFirst(o);
+ queue.notify();
+ }
+ }
+
+ public Object get() throws InterruptedException {
+ synchronized (queue) {
+ if(isClosed) {
+ throw new IllegalStateException("Queue is closed.");
+ }
+ while (queue.isEmpty() & !this.isClosed)
+ queue.wait();
+ Object res=null;
+ try {
+ res=queue.removeFirst();
+ } catch(NoSuchElementException e) {
+ res=null;
+ }
+ return res;
+ }
+ }
+
+ /**
+ * @return
+ */
+ public int size() {
+ return queue.size();
+ }
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/Utils.java b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/Utils.java
new file mode 100644
index 0000000..d4d0422
--- /dev/null
+++ b/apps/MQTTSN-UDP-Client/src/org/eclipse/paho/mqttsn/udpclient/utils/Utils.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.paho.mqttsn.udpclient.utils;
+
+import java.io.UnsupportedEncodingException;
+
+public class Utils {
+
+ public final static String STRING_ENCODING = "UTF-8";
+
+
+ /**
+ * @param data
+ * @return
+ */
+ public static byte[] StringToUTF(String data) {
+ try {
+ byte[] utfBytes = data.getBytes(STRING_ENCODING);
+ byte[] retArray = new byte[utfBytes.length+2];
+
+ retArray[0] = new Integer(utfBytes.length/256).byteValue();
+ retArray[1] = new Integer(utfBytes.length%256).byteValue();
+
+ System.arraycopy( utfBytes, 0, retArray, 2, utfBytes.length);
+ return (retArray);
+ } catch(UnsupportedEncodingException e) {
+ ClientLogger.log(ClientLogger.ERROR, "Utils - Unsupported string encoding: "+STRING_ENCODING);
+ }
+ return null;
+ }
+
+
+ /**
+ * @param data
+ * @param offset
+ * @return
+ */
+ public static String UTFToString(byte[] data, int offset) {
+ if (data == null)
+ return null;
+ int utflen = ((int) (data[0+offset] & 0xFF) << 8) + ((int) (data[1+offset] & 0xFF) << 0);
+ if ((utflen + 2) > data.length)
+ return null;
+
+ String retString = null;
+ if (utflen > 0) {
+ try {
+ retString = new String( data, offset+2, utflen, STRING_ENCODING);
+ } catch( UnsupportedEncodingException e) {
+ ClientLogger.log(ClientLogger.ERROR, "Utils - Unsupported string encoding: "+STRING_ENCODING);
+ }
+ } else {
+ retString = "";
+ }
+
+ return retString;
+ }
+
+
+ /**
+ * @param b
+ * @return
+ */
+ public static String hexString(byte[] b) {
+ String str = "";
+ for(int i = 0; i < b.length; i++) {
+ String t = "00" + Integer.toHexString(b[i]);
+ if(i > 0) str += " ";
+ str += t.substring(t.length() - 2);
+ }
+ return str;
+ }
+
+ public static String hexString0(byte[] b) {
+ String str = "";
+ for(int i = 0; i < b.length; i++) {
+ String t = "00" + Integer.toHexString(b[i]);
+ //if(i > 0) str += " ";
+ str += t.substring(t.length() - 2);
+ }
+ return str.toUpperCase();
+ }
+
+ /**
+ * @param data1
+ * @param data2
+ * @return
+ */
+ public static byte[] concatArray(byte data1[],byte data2[]) {
+ byte temp[] = new byte[data1.length + data2.length];
+ System.arraycopy(data1, 0, temp, 0, data1.length);
+ System.arraycopy(data2, 0, temp, data1.length, data2.length);
+ return (temp);
+ }
+
+
+ /**
+ * @param data1
+ * @param off1
+ * @param len1
+ * @param data2
+ * @param off2
+ * @param len2
+ * @return
+ */
+ public static byte[] concatArray(byte data1[],int off1, int len1, byte data2[], int off2, int len2) {
+ byte temp[] = new byte[len1 + len2];
+ System.arraycopy(data1, off1, temp, 0, len1);
+ System.arraycopy(data2, off2, temp, len1, len2);
+ return (temp);
+ }
+
+ /**
+ * @param data
+ * @param offset
+ * @param length
+ * @return
+ */
+ public static byte[] SliceByteArray(byte data[], int offset, int length) {
+ byte temp[] = new byte[length];
+ System.arraycopy(data, offset, temp, 0, length);
+ return (temp);
+ }
+}
\ No newline at end of file