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