Initial commit of the MQTT-SN Gateway

Change-Id: I0ef1014cd32339d947489a1ac94a7caa269183b1
diff --git a/apps/MQTTSN-Gateway/.classpath b/apps/MQTTSN-Gateway/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/apps/MQTTSN-Gateway/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/apps/MQTTSN-Gateway/.project b/apps/MQTTSN-Gateway/.project
new file mode 100644
index 0000000..1302d1a
--- /dev/null
+++ b/apps/MQTTSN-Gateway/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>MQTT-SN Gateway</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-Gateway/gateway.properties b/apps/MQTTSN-Gateway/gateway.properties
new file mode 100644
index 0000000..efe4c73
--- /dev/null
+++ b/apps/MQTTSN-Gateway/gateway.properties
@@ -0,0 +1,75 @@
+####################################################################################################

+#                                            Mqttsn Gateway parameters                             #

+####################################################################################################

+

+#the ID of the gateway

+gwId = 24

+	

+#the period (in seconds) of broadcasting the Mqtts ADVERTISE message to the network

+advPeriod = 1200

+

+#the period (in seconds) of sending the Mqtt PINGREQ message to the broker

+keepAlivePeriod = 10

+

+#maximum retries of sending a message to the client

+maxRetries = 3

+	

+#maximum time (in seconds) waiting for a message from the client

+waitingTime = 10

+	

+#the time (in seconds) that a ClientMsgHandler can remain inactive

+handlerTimeout = 864000

+

+#the time (in seconds) that a Forwarder can remain inactive

+forwarderTimeout = 300

+	

+#the period (in seconds) that a control message is sent to all ClientMsgHandlers for removing 

+#themselves from Dispatcher's mapping table if they are inactive for at least handlerTimeout seconds

+checkingPeriod = 864000

+	

+#the UDP port that will be used for the UDP socket of the UDPClientInterface

+udpPort = 20000

+	

+#the URL of the broker

+brokerURL = localhost

+	

+#the TCP port where broker listens

+brokerTcpPort = 1883

+

+#serial port parameters

+serialPortURL = serial@COM1:57600

+

+#classes that represent the available client interfaces 

+#clientInterfaces =<org.eclipse.paho.mqttsn.gateway.client.udp.UDPClientInterface>,<org.eclipse.paho.mqttsn.gateway.client.serial.SerialPortClientInterface>

+clientInterfaces =<org.eclipse.paho.mqttsn.gateway.client.udp.UDPClientInterface>

+

+#other parameters of the Mqtt CONNECT message that GatewayMsgHandler sends to the broker

+protocolName = MQIsdp

+protocolVersion = 3

+retain = false

+willQoS = 0

+willFlag = true	

+cleanSession = true

+willTopic = test

+willMessage = bye

+

+#predefined topic ids can take values in [1,N] where N is indicated in predfTopicIdSize

+predfTopicIdSize = 30

+

+#the maximum length of the Mqtts message

+maxMqttsLength = 60

+

+#the minimum length of the Mqtts message

+minMqttsLength = 2

+

+#logging level (INFO,WARN,ERROR) for logging the output messages of the gateway

+logLevel = WARN

+

+#log Dir

+logDir = log

+

+#log file

+logFile = mqtts_gateway.log

+

+#predefined topic ids file 

+predefinedTopicsFile = ./predefinedTopics.properties
diff --git a/apps/MQTTSN-Gateway/predefinedTopics.properties b/apps/MQTTSN-Gateway/predefinedTopics.properties
new file mode 100644
index 0000000..8fd2db4
--- /dev/null
+++ b/apps/MQTTSN-Gateway/predefinedTopics.properties
@@ -0,0 +1,23 @@
+####################################################################################################

+#                                            Predefined Topic Ids                                  #

+####################################################################################################

+

+#representation of the topic id number and the associated topic name 

+#predefined topic ids can take values in [1,N] where N is indicated 

+#in "predfTopicIdSize" property of the gateway.properties file 

+#in all other cases (including error cases) the topic id (and the topic name) will be omitted

+

+1 = predefName1

+2 = predefName1m

+3 = predefName3

+4 = predefName4

+5 = predefName5

+6 = predefName6

+7 = predefName7 

+8 = predefName8

+9 = predefName9

+10 = predefName10

+11 = predefName11

+12 = predefName12

+14 = predefName14

+15 = predefName15

diff --git a/apps/MQTTSN-Gateway/readme.txt b/apps/MQTTSN-Gateway/readme.txt
new file mode 100644
index 0000000..da5ac91
--- /dev/null
+++ b/apps/MQTTSN-Gateway/readme.txt
@@ -0,0 +1,8 @@
+This package contains the Java source code of an MQTT-SN gateway, which could be used to connect
+MQTT-SN clients to an MQTT broker. The main class is defined in
+
+org.eclipse.paho.mqttsn.gateway.Gateway.java
+
+The gateway connects itself to an MQTT broker via the TCP port 1883 and listens on UDP port 20000
+for incoming client connections. These ports numbers, and other variables, are defined in the
+file gateway.properties.
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/Gateway.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/Gateway.java
new file mode 100644
index 0000000..c90c168
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/Gateway.java
@@ -0,0 +1,152 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway;

+

+import java.net.InetAddress;

+import java.net.UnknownHostException;

+import java.text.DateFormat;

+import java.text.SimpleDateFormat;

+import java.util.Date;

+

+import org.eclipse.paho.mqttsn.gateway.core.Dispatcher;

+import org.eclipse.paho.mqttsn.gateway.core.GatewayMsgHandler;

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.timer.TimerService;

+import org.eclipse.paho.mqttsn.gateway.utils.ConfigurationParser;

+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayAddress;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+

+/**

+ * This is the entry point of the MQTT-SN Gateway.

+ * 

+ */

+public class Gateway {

+	private static Dispatcher dispatcher;

+	private static ShutDownHook shutdHook;

+

+

+

+	public void start(String fileName){

+		DateFormat dFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");

+

+		System.out.println();

+		System.out.println(dFormat.format(new Date())+ 

+				"  INFO:  -------- MQTT-SN Gateway starting --------");

+

+		//load the gateway parameters from a file		

+		System.out.println(dFormat.format(new Date())+ 

+				"  INFO:  Loading MQTT-SN Gateway parameters from " + fileName + " ... ");

+		try {

+			ConfigurationParser.parseFile(fileName);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.error("Failed to load Gateway parameters. Gateway cannot start.");

+			System.exit(1);

+		}

+		GatewayLogger.info("Gateway paremeters loaded.");

+

+		//instantiate the timer service

+		TimerService.getInstance();

+

+		//instantiate the dispatcher

+		dispatcher = Dispatcher.getInstance();

+

+		//initialize the dispatcher

+		dispatcher.initialize();		

+

+		//create the address of the gateway itself(see org.eclipse.paho.mqttsn.gateway.utils.GatewayAdress)

+		int len = 1;

+		byte[] addr = new byte[len];

+		addr[0] = (byte)GWParameters.getGwId();

+

+		InetAddress ip = null;

+

+		try {

+			ip = InetAddress.getLocalHost();

+		} catch (UnknownHostException e) {			

+			e.printStackTrace();

+			GatewayLogger.error("Failed to create the address of the Gateway.Gateway cannot start.");

+			System.exit(1);

+		}

+

+		int port = GWParameters.getUdpPort();

+

+		GatewayAddress gatewayAddress = new GatewayAddress(addr,ip,port);

+		GWParameters.setGatewayAddress(gatewayAddress);		

+

+

+		//create a new GatewayMsgHandler (for the connection of the gateway itself)		

+		GatewayMsgHandler gatewayHandler = new GatewayMsgHandler(GWParameters.getGatewayAddress());

+

+		//insert this handler to the Dispatcher's mapping table

+		dispatcher.putHandler(GWParameters.getGatewayAddress(), gatewayHandler);

+

+		//initialize the GatewayMsgHandler

+		gatewayHandler.initialize();

+

+		//connect to the broker

+		gatewayHandler.connect();

+

+		//add a "listener" for catching shutdown events (Ctrl+C,etc.)

+		shutdHook = new ShutDownHook(); 

+		Runtime.getRuntime().addShutdownHook(shutdHook);		

+	}

+

+	/**

+	 * 

+	 */

+	public static void shutDown(){

+		//generate a control message 

+		ControlMessage controlMsg = new ControlMessage();

+		controlMsg.setMsgType(ControlMessage.SHUT_DOWN);

+

+		//construct an "internal" message and put it to dispatcher's queue

+		//@see org.eclipse.paho.mqttsn.gateway.core.Message

+		Message msg = new Message(null);

+		msg.setType(Message.CONTROL_MSG);

+		msg.setControlMessage(controlMsg);

+		dispatcher.putMessage(msg);

+	}

+

+

+	/**

+	 *

+	 */

+	private class ShutDownHook extends Thread{

+		public void run(){

+			shutDown();	

+		}

+	}

+

+

+	/**

+	 * @param args

+	 */

+	public static void main(String[] args) {

+		String fileName = "gateway.properties";

+		if (args.length > 0) fileName = args[0];

+		Gateway gateway = new Gateway();

+		gateway.start(fileName);		

+	}

+

+	public static void removeShutDownHook() {

+		Runtime.getRuntime().removeShutdownHook(shutdHook);		

+	}	

+}
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/BrokerInterface.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/BrokerInterface.java
new file mode 100644
index 0000000..062f625
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/BrokerInterface.java
@@ -0,0 +1,54 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.broker;

+

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+

+/**

+ * 

+ * This class represents the interface over which the gateway send 

+ * Mqtt messages to the the broker and vice versa.

+ * 

+ */

+public interface BrokerInterface {

+

+

+	/**

+	 * The method that initializes the broker interface.

+	 */

+	public void initialize() throws MqttsException;

+

+

+	/**

+	 * The method that reads a Mqtt Message from the broker.

+	 */

+	public void readMsg();

+

+

+	/**

+	 * The method that sends a Mqtt message to the broker.

+	 * @param msg The Mqtt message to be sent.

+	 */

+	public void sendMsg(MqttMessage msg)throws MqttsException;

+

+

+	/**

+	 * The method that disconnects from the broker.

+	 */

+	public void disconnect();

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/tcp/TCPBrokerInterface.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/tcp/TCPBrokerInterface.java
new file mode 100644
index 0000000..86ea9b4
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/broker/tcp/TCPBrokerInterface.java
@@ -0,0 +1,388 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.broker.tcp;

+

+import java.io.DataInputStream;

+import java.io.DataOutputStream;

+import java.io.EOFException;

+import java.io.IOException;

+import java.io.InterruptedIOException;

+import java.net.Socket;

+import java.net.UnknownHostException;

+

+import org.eclipse.paho.mqttsn.gateway.broker.BrokerInterface;

+import org.eclipse.paho.mqttsn.gateway.core.Dispatcher;

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttConnack;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingResp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubComp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRec;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRel;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPublish;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttSuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttUnsuback;

+import org.eclipse.paho.mqttsn.gateway.utils.Address;

+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+/**

+ * This class represents the interface to the broker and is instantiated by the 

+ * MessageHandler.Is is used for opening a TCP/IP connection with the broker 

+ * and sending/receiving Mqtt Messages.

+ * For the reading functionality a reading thread is created. 

+ * For every client there is one instance of this class. 

+ * 

+ * @see com.ibm.zurich.core.ClientMsgHandler

+ * 

+ * Parts of this code were imported from com.ibm.mqttdirect.modules.common.StreamDeframer.java

+ * 

+ *

+ */

+public class TCPBrokerInterface implements BrokerInterface, Runnable {

+

+	private	DataInputStream	 streamIn	= null;		

+	private	DataOutputStream streamOut	= null;

+	private Socket socket;

+

+	private Address address;

+	private String brokerURL;

+	private int port;

+	private String clientId;

+

+	private volatile boolean running;	

+	private Thread readThread;

+

+	private Dispatcher dispatcher;

+

+	//the maximum length of a Mqtt fixed header

+	public static final int MAX_HDR_LENGTH = 5;

+

+	//the maximum length of the remaining part of a Mqtt message

+	public static final int MAX_MSG_LENGTH = 268435455;

+

+

+	/**

+	 * Constructor of the broker interface.

+	 */

+	public TCPBrokerInterface(Address address) {

+		this.address = address;

+		this.brokerURL = GWParameters.getBrokerURL();

+		this.port = GWParameters.getBrokerTcpPort();

+		this.running = false;

+		this.readThread = null;

+		this.dispatcher = Dispatcher.getInstance();

+	}

+

+	/**

+	 * This method opens the TCP/IP connection with the broker and creates 

+	 * a new thread for reading from the socket.

+	 * 

+	 * @throws MqttsException 

+	 */

+	public void initialize() throws MqttsException{

+		try {

+			socket = new Socket(brokerURL, port);

+			streamIn = new DataInputStream(socket.getInputStream());

+			streamOut = new DataOutputStream(socket.getOutputStream());			

+

+		} catch (UnknownHostException e) {

+			disconnect();

+			throw new MqttsException(e.getMessage());

+		} catch (IOException e) {

+			disconnect();			

+			throw new MqttsException(e.getMessage());

+		}

+

+		//create thread for reading

+		this.readThread = new Thread (this, "BrokerInterface");

+		this.running = true;

+		this.readThread.start();

+	}

+

+

+	/**

+	 * This method sends a Mqtt message to the broker over the already established 

+	 * TCP/IP connection.Before that, converts the message to byte array calling

+	 * the method {@link org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage#toBytes()}.

+	 * 

+	 * @param message The MqttMessage to be send to the broker.

+	 * @throws MqttsException 

+	 */

+	public void sendMsg(MqttMessage message) throws MqttsException{

+		// send the message over the TCP/IP socket

+		if (this.streamOut != null) {

+			try {

+				//System.out.println(">> sending msg: " + Utils.hexString(message.toBytes()));

+				this.streamOut.write(message.toBytes());

+				this.streamOut.flush();

+			} catch (IOException e) {

+				disconnect();

+				throw new MqttsException(e.getMessage());

+			}

+		}else{

+			disconnect();

+			throw new MqttsException("Writing stream is null!");

+		}

+	}

+

+	/**

+	 * This method is used for reading a Mqtt message from the socket.It blocks on the 

+	 * reading stream until a message arrives.

+	 */

+	public void readMsg(){

+		byte [] body = null;

+

+		// read the header from the input stream

+		MqttHeader hdr = new MqttHeader();

+		hdr.header = new byte[MAX_HDR_LENGTH];

+

+		if (this.streamIn == null){

+			return;

+		}

+

+		try{

+			int res = streamIn.read();

+			hdr.header[0]=(byte) res;

+			hdr.headerLength=1; 

+			if(res==-1) {

+				// if EOF detected

+				throw new EOFException();

+			}

+			// read the Mqtt length

+			int multiplier = 1;

+			hdr.remainingLength=0;

+			do {

+				//read MsgLength bytes

+				res = streamIn.read();

+				if(res==-1) {

+					// if EOF detected.

+					throw new EOFException();

+				}

+				hdr.header[hdr.headerLength++] = (byte) res;

+				hdr.remainingLength += (res & 127) * multiplier;

+				multiplier *= 128;

+			} while ((res & 128) != 0 && hdr.headerLength<MAX_HDR_LENGTH);

+

+			//some checks

+			if (hdr.headerLength > MAX_HDR_LENGTH || hdr.remainingLength > MAX_MSG_LENGTH || hdr.remainingLength < 0) {

+				GatewayLogger.log(GatewayLogger.WARN, "TCPBrokerInterface ["+Utils.hexString(this.address.getAddress())+"]/["+clientId+"] - Not a valid Mqtts message.");

+				return;

+			}			

+

+			body = new byte[hdr.remainingLength+hdr.headerLength]; 

+

+			for (int i = 0; i < hdr.headerLength; i++) {

+				body[i] = hdr.header[i]; 

+			}

+

+			if (hdr.remainingLength >= 0) {

+				streamIn.readFully(body, hdr.headerLength, hdr.remainingLength);

+			}

+

+

+			//start:just for the testing purposes we simulate here a network delay

+			//TODO This will NOT be included in the final version

+			try {

+				Thread.sleep(20);

+			} catch (InterruptedException e) {

+				// TODO Auto-generated catch block

+				e.printStackTrace();

+			}

+			//end			

+

+

+			if(body!=null)

+				decodeMsg(body);

+		}catch(IOException e){

+			if(e instanceof InterruptedIOException) {

+				//do nothing

+			}else if(this.running == true){

+				//an error occurred

+				//stop the reading thread

+				this.running = false;

+

+				//generate a control message 

+				ControlMessage controlMsg = new ControlMessage();

+				controlMsg.setMsgType(ControlMessage.CONNECTION_LOST);

+

+				//construct an "internal" message and put it to dispatcher's queue

+				//@see org.eclipse.paho.mqttsn.gateway.core.Message

+				Message msg = new Message(this.address);

+				msg.setType(Message.CONTROL_MSG);

+				msg.setControlMessage(controlMsg);

+				this.dispatcher.putMessage(msg);

+			}

+		} 

+	}

+

+	/**

+	 * This method is used for decoding the received Mqtt message from the broker.

+	 * @param data The Mqtt message as it was received from the socket (byte array).

+	 */

+	private void decodeMsg(byte[] data){

+		MqttMessage mqttMsg = null;

+		int msgType = (data[0] >>> 4) & 0x0F;

+		switch (msgType) {

+		case MqttMessage.CONNECT:

+			// we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.CONNACK:

+			mqttMsg = new MqttConnack(data);

+			break;

+

+		case MqttMessage.PUBLISH:

+			mqttMsg = new MqttPublish(data);

+			break;

+

+		case MqttMessage.PUBACK:

+			mqttMsg = new MqttPuback(data);

+			break;

+

+		case MqttMessage.PUBREC:

+			mqttMsg = new MqttPubRec(data);

+			break;

+

+		case MqttMessage.PUBREL:

+			mqttMsg = new MqttPubRel(data);

+			break;

+

+		case MqttMessage.PUBCOMP:

+			mqttMsg = new MqttPubComp(data);

+			break;

+

+		case MqttMessage.SUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.SUBACK:

+			mqttMsg = new MqttSuback(data);

+			break;

+

+		case MqttMessage.UNSUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.UNSUBACK:

+			mqttMsg = new MqttUnsuback(data);

+			break;

+

+		case MqttMessage.PINGREQ:

+			mqttMsg = new MqttPingReq(data);

+			break;

+

+		case MqttMessage.PINGRESP:

+			mqttMsg = new MqttPingResp(data);

+			break;

+

+		case MqttMessage.DISCONNECT:

+			//we will never receive such a message from the broker

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "TCPBrokerInterface ["+Utils.hexString(this.address.getAddress())+"]/["+clientId+"] - Mqtt message of unknown type \"" + msgType+"\" received.");

+			break;				

+		}

+

+		//construct an "internal" message and put it to dispatcher's queue

+		//@see org.eclipse.paho.mqttsn.gateway.core.Message

+		Message msg = new Message(this.address);

+		msg.setType(Message.MQTT_MSG);

+		msg.setMqttMessage(mqttMsg);

+		this.dispatcher.putMessage(msg);		

+	}

+

+

+	/**

+	 */

+	public void disconnect() {

+		//stop the reading thread (if any)

+		this.running = false;

+

+		//close the out stream

+		if (this.streamOut != null) {

+			try {

+				this.streamOut.flush();

+				this.streamOut.close();

+			} catch (IOException e) {

+				// ignore it

+			}

+			this.streamOut = null;

+		}	

+

+		//close the in stream

+		if (this.streamIn != null) {

+			try {

+				this.streamIn.close();

+			} catch (IOException e) {

+				// ignore it

+			}

+			streamIn = null;

+		}	

+

+		//close the socket

+		if (socket != null) {

+			try {

+				socket.close();

+			} catch (IOException e) {

+			}

+			socket = null;

+		}

+	}

+

+

+	/* (non-Javadoc)

+	 * @see java.lang.Runnable#run()

+	 */

+	public void run() {

+		while (running) {

+			readMsg();

+		}

+	}

+

+

+	/**

+	 * @param running

+	 */

+	public void setRunning(boolean running) {

+		this.running = running;

+	}	

+

+	/**

+	 * @param clientId

+	 */

+	public void setClientId(String clientId) {

+		this.clientId = clientId;

+	}

+

+

+	/**

+	 * This class represents a Mqtt header and is used for decoding a Mqtt message

+	 * from the broker.

+	 */

+	public static class MqttHeader {

+		public byte[]	header;

+		public int remainingLength;

+		public int headerLength;

+	}

+}    	
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/ClientInterface.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/ClientInterface.java
new file mode 100644
index 0000000..69ddf7d
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/ClientInterface.java
@@ -0,0 +1,59 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.client;

+

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+import org.eclipse.paho.mqttsn.gateway.utils.ClientAddress;

+

+

+/**

+ * 

+ * This class represents the interface over which the clients send 

+ * Mqtts messages to the gateway and vice versa.

+ * 

+ */

+public interface ClientInterface {	

+		

+	/**

+	 * The method that initializes the client interface.

+	 */

+	public void initialize() throws MqttsException;

+	

+	

+	/**

+	 * The method that sends a Mqtts message to the specified SA client (unicast).

+	 * @param address The unique address of the SA client.

+	 * @param msg The Mqtts message to be sent.

+	 */

+	public void sendMsg(ClientAddress address, MqttsMessage msg);

+	

+	

+	/**

+	 * The method that broadcasts a Mqtts Message to the network.

+	 * @param msg The Mqtt message to be broadcasted.

+	 */

+	public void broadcastMsg(MqttsMessage msg);

+	

+	

+	/**

+	 * The method that broadcasts a Mqtts message to the network within a specific radius.

+	 * @param radius The broadcast radius of the Mqtt message.

+	 * @param msg The Mqtt message to be broadcasted.

+	 */

+	public void broadcastMsg(int radius, MqttsMessage msg);

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/udp/UDPClientInterface.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/udp/UDPClientInterface.java
new file mode 100644
index 0000000..1860252
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/client/udp/UDPClientInterface.java
@@ -0,0 +1,567 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2014 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.gateway.client.udp;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+//import java.net.SocketException;
+import java.util.Vector;
+
+import org.eclipse.paho.mqttsn.gateway.client.ClientInterface;
+//import org.eclipse.paho.mqttsn.gateway.client.udp.UDPClientInterface.Forwarder;
+import org.eclipse.paho.mqttsn.gateway.core.Dispatcher;
+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;
+import org.eclipse.paho.mqttsn.gateway.messages.Message;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsAdvertise;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsConnect;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsDisconnect;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsGWInfo;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPingReq;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPingResp;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubComp;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubRec;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubRel;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPuback;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPublish;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsRegack;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsRegister;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSearchGW;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSubscribe;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsUnsubscribe;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillMsg;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillMsgUpd;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillTopic;
+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillTopicUpd;
+import org.eclipse.paho.mqttsn.gateway.utils.ClientAddress;
+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;
+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;
+import org.eclipse.paho.mqttsn.gateway.utils.Utils;
+
+/**
+ * This class implements a UDP interface to Mqtts clients.Implements the 
+ * interface {@link org.eclipse.paho.mqttsn.gateway.client.ClientInterface}.
+ * For the reading functionality a reading thread is created. 
+ * There is only one instance of this class. 
+ * 
+ */
+public class UDPClientInterface implements ClientInterface, Runnable {
+
+	private DatagramSocket udpSocket;
+	private volatile boolean running;
+	private Thread readThread;
+	private Vector<Forwarder> forwarders;
+	private Dispatcher dispatcher;
+	private byte[] recData = new byte[512];
+
+
+	/**
+	 * This method initializes the interface.It creates an new UDP socket and
+	 * a new thread for reading from the socket.
+	 * @throws MqttsException 
+	 */
+	public void initialize() throws MqttsException {
+		try {
+			//create the udp socket 
+			udpSocket = new DatagramSocket(GWParameters.getUdpPort());
+
+			//get the Dispatcher
+			dispatcher = Dispatcher.getInstance();
+
+			forwarders = new Vector<Forwarder>();
+
+			//create thread for reading
+			this.readThread = new Thread (this, "UDPClientInterface");
+			this.running = true;
+			this.readThread.start();
+		} catch (Exception e) {
+			throw new MqttsException ("UDPClientInterface - Error initializing :" +e);
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.paho.mqttsn.gateway.client.ClientInterface#broadcastMsg(org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage)
+	 */
+	public void broadcastMsg(MqttsMessage msg) {
+		//		GatewayLogger.log(GatewayLogger.INFO, "UDPClientInterface - Broadcasting Mqtts \"" +Utils.hexString(msg.toBytes())+"\" message to the network.");
+		for(int i = forwarders.size() - 1; i >= 0; i--) {
+			Forwarder fr = (Forwarder)forwarders.get(i);
+			//check also if this forwarder is inactive
+			if (System.currentTimeMillis() > fr.timeout)
+				forwarders.remove(i);
+			else{
+				try {
+					byte[] wireMsg = msg.toBytes();
+					byte[] data = new byte[wireMsg.length + 2];
+					data[0] = (byte)0x00;//0x00 means broadcast to all network
+					data[1] = (byte)0x00;
+					System.arraycopy(wireMsg, 0, data, 2, wireMsg.length);
+					DatagramPacket packet = new DatagramPacket(data, data.length, fr.addr, fr.port);
+					udpSocket.send(packet);
+				} catch (IOException e) {
+					GatewayLogger.log(GatewayLogger.ERROR, "UDPClientInterface - Error while writing on the UDP socket.");
+				}
+			}
+		}
+	}		
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.paho.mqttsn.gateway.client.ClientInterface#broadcastMsg(int, org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage)
+	 */
+	public void broadcastMsg(int radius, MqttsMessage msg) {
+		//		GatewayLogger.log(GatewayLogger.INFO, "UDPClientInterface - Broadcasting Mqtts \"" +Utils.hexString(msg.toBytes())+"\" message to the network with broadcast radius "+radius+".");
+		for(int i = forwarders.size() - 1; i >= 0; i--) {
+			Forwarder fr = (Forwarder)forwarders.get(i);
+			//check also if this forwarder is inactive
+			if (System.currentTimeMillis() > fr.timeout)
+				forwarders.remove(i);
+			else{
+				try {
+					byte[] wireMsg = msg.toBytes();
+					byte[] data = new byte[wireMsg.length + 2];
+					data[0] = (byte)radius;//broadcast to the specified radius
+					data[1] = (byte)0x00;
+					System.arraycopy(wireMsg, 0, data, 2, wireMsg.length);
+					DatagramPacket packet = new DatagramPacket(data, data.length, fr.addr, fr.port);
+					udpSocket.send(packet);
+				} catch (IOException e) {
+					GatewayLogger.log(GatewayLogger.ERROR, "UDPClientInterface - Error while writing on the UDP socket.");
+				}
+			}
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.paho.mqttsn.gateway.client.ClientInterface#readMsg()
+	 */
+	public void readMsg() {
+		DatagramPacket packet = new DatagramPacket(recData,0, recData.length);
+		try {
+			packet.setLength(recData.length);
+			udpSocket.receive(packet);
+
+			//add the forwarder from which we received the message to the list
+			//if it is already on the list just update its timeout
+			Forwarder forw = new Forwarder();
+			forw.addr = packet.getAddress();
+			forw.port = packet.getPort();
+			forw.timeout = System.currentTimeMillis() + GWParameters.getForwarderTimeout()*1000;
+			//GatewayLogger.log(GatewayLogger.INFO, "UDPClientInterface -  New forwarder:addr = " + forw.addr+ " port = "+forw.port);
+
+			boolean found = false;
+			for(int i = 0 ; i < forwarders.size(); i++) {
+				Forwarder fr = (Forwarder)forwarders.get(i);
+				if(forw.equals(fr)){
+					found = true;
+					fr.timeout = System.currentTimeMillis() + GWParameters.getForwarderTimeout()*1000;
+					break;
+				}				
+			}			
+			if (!found) forwarders.add(forw);
+		
+//			if(packet.getLength() > 3) { // not a keep alive packet
+				byte[] data = new byte[packet.getLength()];
+				System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());
+				
+				//old encaps v1.1
+//				byte[] clAddr = new byte[data[1]];  //data[1] contains length of clAddr (wireless node id)
+//				System.arraycopy(data, 2, clAddr, 0, clAddr.length);
+//				ClientAddress address = new ClientAddress(clAddr, packet.getAddress(), packet.getPort());
+//				byte[] mqttsData = new byte[data.length - clAddr.length - 2];
+//				System.arraycopy(data, clAddr.length + 2, mqttsData, 0, mqttsData.length);
+				//end old encaps v1.1
+				
+				byte[] mqttsData = null;
+				ClientAddress address = null;
+				
+				if (data[0] == (byte)0x00) {  //old encaps v 1.1
+					byte[] clAddr = new byte[data[1]];  //data[1] contains length of clAddr (wireless node id)
+					System.arraycopy(data, 2, clAddr, 0, clAddr.length);
+					byte[] encaps = new byte[data[1]+2];
+					System.arraycopy(data, 0, encaps, 0, encaps.length);
+					address = new ClientAddress(clAddr, packet.getAddress(), packet.getPort(), true, encaps);
+					mqttsData = new byte[data.length - clAddr.length - 2];
+					System.arraycopy(data, clAddr.length + 2, mqttsData, 0, mqttsData.length);
+				} else if (data[1] == (byte)MqttsMessage.ENCAPSMSG) { //new encaps v1.2
+					//we have an encapsulated msg
+					byte[] clAddr = new byte[((int)data[0]&0xFF) - 3];  //data[0]: length of encaps
+					System.arraycopy(data, 3, clAddr, 0, clAddr.length);
+					byte[] encaps = new byte[data[0]];
+					System.arraycopy(data, 0, encaps, 0, encaps.length);
+					address = new ClientAddress(clAddr, packet.getAddress(), packet.getPort(), true, encaps);
+					mqttsData = new byte[(int)data[data[0]]];
+					System.arraycopy(data, data[0], mqttsData, 0, mqttsData.length);
+				} else {
+					//we have a non-encapsulated mqtts msg
+					//we will create an address out of the forwarder address
+					byte[] a1 = packet.getAddress().getAddress();
+					byte[] a2 = new byte[2];
+					a2[0] = (byte)((packet.getPort() >> 8) & 0xFF);
+					a2[1] = (byte) ( packet.getPort() & 0xFF);
+					byte[] clAddr = new byte[a1.length+a2.length];
+					System.arraycopy(a1, 0, clAddr, 0, a1.length);
+					System.arraycopy(a2, 0, clAddr, a1.length, a2.length);
+					address = new ClientAddress(clAddr, packet.getAddress(), packet.getPort(), false, null);
+					mqttsData = new byte[(int)data[0]];
+					System.arraycopy(data, 0, mqttsData, 0, mqttsData.length);
+				}
+				
+				
+//start-just for the testing purposes we simulate here a network delay
+//This will NOT be included in the final version
+//				try {
+//					Thread.sleep(10);
+//				} catch (InterruptedException e) {
+//					// TODO Auto-generated catch block
+//					e.printStackTrace();
+//				}
+
+				//end
+				decodeMsg(mqttsData,address);
+//			}
+		}catch (IOException ex){
+			ex.printStackTrace();
+			GatewayLogger.log(GatewayLogger.ERROR, "UDPClientInterface - An I/O error occurred while reading from the socket.");
+		}
+	}
+
+	/**
+	 * This method decodes the received Mqtts message and then constructs a 
+	 * general "internal" message {@link org.eclipse.paho.mqttsn.gateway.messages.Message}
+	 * which puts it to Dispatcher's queue {@link  org.eclipse.paho.mqttsn.gateway.core.Dispatcher.
+	 * 
+	 * @param data The received Mqtts packet.
+	 * @param address The address of the SA client.
+	 */
+	public void decodeMsg(byte[] data, ClientAddress address) {
+		MqttsMessage mqttsMsg = null;
+
+		//do some checks for the received packet
+		if(data == null) {
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - The received data packet is null. The packet cannot be processed.");
+			return;
+		}
+
+		if(data.length < GWParameters.getMinMqttsLength()) {
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts message. The received data packet is too short (length = "+data.length +"). The packet cannot be processed.");
+			return;
+		}
+
+		if(data.length > GWParameters.getMaxMqttsLength()){
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts message. The received data packet is too long (length = "+data.length +"). The packet cannot be processed.");
+			return;
+
+		}
+
+		if(data[0] < GWParameters.getMinMqttsLength()) {
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts message. Field \"Length\" in the received data packet is less than "+GWParameters.getMinMqttsLength()+" . The packet cannot be processed.");
+			return;
+		}
+
+		if(data[0] != data.length) {
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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.");
+			return;
+		}
+
+
+		int msgType = (data[1] & 0xFF);
+		switch (msgType) {
+		case MqttsMessage.ADVERTISE:
+			if(data.length != 5) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts ADVERTISE message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+			mqttsMsg = new MqttsAdvertise(data);
+			//TODO Handle this case for load balancing issues
+			break;
+
+		case MqttsMessage.SEARCHGW:
+			if(data.length != 3) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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);
+			//TODO Handle this case for load balancing issues
+			break;
+
+		case MqttsMessage.CONNECT:
+			if(data.length < 7) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts CONNECT message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+			mqttsMsg = new MqttsConnect(data);
+			break;
+
+		case MqttsMessage.CONNACK:
+			//we will never receive such a message from the client
+			break;
+
+		case MqttsMessage.WILLTOPICREQ:
+			//we will never receive such a message from the client
+			break;
+
+		case MqttsMessage.WILLTOPIC:
+			if(data.length < 2) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts WILLTOPIC message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+			mqttsMsg = new MqttsWillTopic(data);
+			break;
+
+		case MqttsMessage.WILLMSGREQ:
+			//we will never receive such a message from the client
+			break;
+
+		case MqttsMessage.WILLMSG:
+			if(data.length < 3) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts WILLMSG message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+			mqttsMsg = new MqttsWillMsg(data);
+			break;
+
+		case MqttsMessage.REGISTER:
+			if(data.length < 7) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - 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:
+			if(data.length < 6) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts SUBSCRIBE message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+
+			try {
+				mqttsMsg = new MqttsSubscribe(data);
+			} catch (MqttsException e) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts SUBSCRIBE message. "+e.getMessage());
+				return;
+			}
+			break;
+
+		case MqttsMessage.SUBACK:
+			//we will never receive such a message from the client
+			break;
+
+		case MqttsMessage.UNSUBSCRIBE :
+			if(data.length < 6) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts UNSUBSCRIBE message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+
+			try {
+				mqttsMsg = new MqttsUnsubscribe(data);
+			} catch (MqttsException e) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts UNSUBSCRIBE message. "+e.getMessage());
+				return;
+			}
+			break;
+
+		case MqttsMessage.UNSUBACK:
+			//we will never receive such a message from the client
+			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:
+			if(data.length < 2) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts WILLTOPICUPD message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+
+			mqttsMsg = new MqttsWillTopicUpd(data);
+			break;
+
+		case MqttsMessage.WILLTOPICRESP:
+			//we will never receive such a message from the client
+			break;
+
+		case MqttsMessage.WILLMSGUPD:
+			if(data.length < 3) {
+				GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Not a valid Mqtts WILLMSGUPD message. Wrong packet length (length = "+data.length +"). The packet cannot be processed.");
+				return;
+			}
+
+			mqttsMsg = new MqttsWillMsgUpd(data);
+			break;
+
+		case MqttsMessage.WILLMSGRESP:
+			//we will never receive such a message from the client
+			break;
+
+		default:
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - Mqtts message of unknown type \"" + msgType+"\" received.");
+			return;
+		}
+
+		//construct an "internal" message and put it to dispatcher's queue
+		Message msg = new Message(address);
+		msg.setType(Message.MQTTS_MSG);
+		msg.setMqttsMessage(mqttsMsg);
+		msg.setClientInterface(this);
+		this.dispatcher.putMessage(msg);		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.paho.mqttsn.gateway.client.ClientInterface#sendMsg(org.eclipse.paho.mqttsn.gateway.utils.SAaddress, org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage)
+	 */
+	public void sendMsg(ClientAddress address, MqttsMessage msg) {
+		//		GatewayLogger.log(GatewayLogger.INFO, "UDPClientInterface - Sending Mqtts \"" + Utils.hexString(msg.toBytes())+ "\" message to the client with address \"" +Utils.hexString(address.getAddress())+"\".");
+
+		if(address == null) {
+			GatewayLogger.log(GatewayLogger.WARN, "UDPClientInterface - The address of the receiver is null.The Mqtts message " + Utils.hexString(msg.toBytes())+ " cannot be sent.");
+			return;
+		}
+
+		try {
+			byte[] addr = address.getAddress();
+			byte[] wireMsg = msg.toBytes();
+			
+			//old encaps v1.1
+//			byte[] data = new byte[wireMsg.length + addr.length + 2];
+//			data[0] = (byte)0x00;
+//			data[1] = (byte)addr.length;
+//			System.arraycopy(addr, 0, data, 2, addr.length);
+//			System.arraycopy(wireMsg,  0, data, addr.length + 2, wireMsg.length);
+			//end old encaps v1.1
+			
+			//new encaps v1.2
+			byte[] data = null;
+			if (address.isEncaps()) {
+//				byte[] encaps = new byte[3+addr.length];
+//				encaps[0] = (byte)(addr.length + 3);
+//				encaps[1] = (byte) MqttsMessage.ENCAPSMSG;
+//				encaps[2] = 0x00;
+				byte[] encaps = address.getEncaps();
+				System.arraycopy(addr, 0, encaps, 0, addr.length);
+				data = new byte[encaps.length + wireMsg.length];
+				System.arraycopy(encaps, 0, data, 0, encaps.length);
+				System.arraycopy(wireMsg, 0, data, encaps.length, wireMsg.length);				
+			} else {
+				data = wireMsg;
+			}
+			//end new encaps v1.2
+			
+			DatagramPacket packet = new DatagramPacket(data, data.length, address.getIPaddress(), address.getPort());
+			udpSocket.send(packet);
+		} catch (IOException e) {
+			e.printStackTrace();
+			GatewayLogger.log(GatewayLogger.ERROR, "UDPClientInterface - Error while writing on the UDP socket.");
+		}
+	}
+
+
+	/* (non-Javadoc)
+	 * @see java.lang.Runnable#run()
+	 */
+	public void run() {
+		while (running) {
+			readMsg();
+		}
+	}
+
+
+	/**
+	 * This class represents a forwarder which is defined in the specifications of the
+	 * Mqtts protocol.
+	 */
+	public static class Forwarder {
+		private InetAddress addr = null;
+		private int port = 0;
+		private long timeout = 0;
+
+		public boolean equals(Object o) {
+			boolean same = false;
+			if(o == null) {
+				same = false;
+			} else if(o instanceof Forwarder) {
+				Forwarder fr = (Forwarder)o;
+				if(addr != null && addr.equals(fr.addr) && fr.port == port) {
+					same = true;
+				}
+			}
+			return same;
+		}
+	}
+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/ClientMsgHandler.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/ClientMsgHandler.java
new file mode 100644
index 0000000..b1d54dc
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/ClientMsgHandler.java
@@ -0,0 +1,2387 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.core;

+

+import org.eclipse.paho.mqttsn.gateway.broker.tcp.TCPBrokerInterface;

+import org.eclipse.paho.mqttsn.gateway.client.ClientInterface;

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttConnack;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttConnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttDisconnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingResp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubComp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRec;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRel;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPublish;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttSuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttSubscribe;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttUnsuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttUnsubscribe;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsConnack;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsConnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsDisconnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPingReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPingResp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubComp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubRec;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPubRel;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPublish;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsRegack;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsRegister;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSearchGW;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSubscribe;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsUnsuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsUnsubscribe;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillMsg;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillMsgReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillMsgUpd;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillTopic;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillTopicReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsWillTopicUpd;

+import org.eclipse.paho.mqttsn.gateway.timer.TimerService;

+import org.eclipse.paho.mqttsn.gateway.utils.ClientAddress;

+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayAddress;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+/**

+ * This object implements the core functions of the protocol translation.

+ * For each client there is one instance of this object.Every message (Mqtt, 

+ * Mqtts or Control)

+ * that corresponds to a certain client, is handled by this object.

+ *

+ */

+public class ClientMsgHandler extends MsgHandler{

+

+	//the unique address of the client that distinguishes this object

+	private ClientAddress clientAddress = null;

+

+	//the clientId of the client(the one that is sent in Mqtts CONNECT message)

+	private String clientId = "...";

+

+	//the ClientInterface (IP, Serial, etc.) in which this object should 

+	//respond in case of sending a Mqtts message to the client 

+	private ClientInterface clientInterface = null;

+

+	//the BrokerInterface which represents an interface for communication with the broker

+	private TCPBrokerInterface brokerInterface = null;

+

+	//a timer service which is used for timeouts

+	private TimerService timer = null;

+

+	//a table that is used for mapping topic Ids with topic names

+	private TopicMappingTable topicIdMappingTable = null;

+

+	//a reference to Dispatcher object

+	private Dispatcher dispatcher = null;

+

+	//class that represents the state of the client at any given time

+	private ClientState client = null;

+

+	//class that represents the state of the gateway (actually this handler's state) at any given time

+	private GatewayState gateway = null;

+

+	//variable for checking the time of inactivity of this object 

+	//in order to remove it from Dispatcher's mapping table

+	private long timeout;

+

+	//messages for storing the information while on a connection procedure  

+	private MqttsConnect mqttsConnect = null;

+	private MqttsWillTopic mqttsWillTopic = null;	

+

+	//messages for storing information while on a subscribe/unsubscribe procedure 

+	private MqttsSubscribe mqttsSubscribe = null;

+	private MqttsUnsubscribe mqttsUnsubscribe = null;

+

+	//message for storing information while on registration procedure initiated by the gateway

+	private MqttsRegister mqttsRegister = null;

+

+	//message for storing information (if necessary) when we receive a Mqtt PUBLISH message

+	private MqttPublish mqttPublish = null;

+

+	//message for storing information (if necessary) when we receive a Mqtts PUBLISH message

+	private MqttsPublish mqttsPublish = null;

+

+

+	//variables for handling Mqtts messages WILLTOPICUPD and WILLMSGUPD

+	//private String willtopic = "";

+	//private String willMessage = "";

+

+	//variables for storing the msgId and topicId that are issued by the gateway

+	private int msgId;

+	private int topicId;

+

+

+	/**

+	 * Constructor of the ClientMsgHandler.

+	 * 

+	 * @param addr The address of the client.

+	 */

+	public ClientMsgHandler(ClientAddress addr){

+		this.clientAddress = addr;

+	}

+

+

+	/* (non-Javadoc)

+	 * @see org.eclipse.paho.mqttsn.gateway.core.MsgHandler#initialize()

+	 */

+	public void initialize() {

+		brokerInterface = new TCPBrokerInterface(this.clientAddress);

+		brokerInterface.setClientId(clientId);

+		timer = TimerService.getInstance();

+		dispatcher = Dispatcher.getInstance();

+		topicIdMappingTable = new TopicMappingTable();

+		topicIdMappingTable.initialize();

+		timeout = 0;

+		client = new ClientState();

+		gateway = new GatewayState();

+		msgId = 1;

+		topicId = GWParameters.getPredfTopicIdSize()+1;

+	}

+

+

+

+	/******************************************************************************************/

+	/**                      HANDLING OF MQTTS MESSAGES FROM THE CLIENT                     **/

+	/****************************************************************************************/

+

+	/* (non-Javadoc)

+	 * @see org.eclipse.paho.mqttsn.gateway.core.MsgHandler#handleMqttsMessage(org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage)

+	 */

+	public void handleMqttsMessage(MqttsMessage receivedMsg){		

+		//update this handler's timeout

+		timeout = System.currentTimeMillis() + GWParameters.getHandlerTimeout()*1000;

+

+		//get the type of the Mqtts message and handle the message according to that type	

+		switch(receivedMsg.getMsgType()){

+		case MqttsMessage.ADVERTISE:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.SEARCHGW:

+			handleMqttsSearchGW((MqttsSearchGW) receivedMsg);

+			break;

+

+		case MqttsMessage.GWINFO:

+			//we will never receive such a message from the client

+			break;				

+

+		case MqttsMessage.CONNECT:

+			handleMqttsConnect((MqttsConnect) receivedMsg);

+			break;

+

+		case MqttsMessage.CONNACK:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.WILLTOPICREQ:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.WILLTOPIC:

+			handleMqttsWillTopic((MqttsWillTopic)receivedMsg);

+			break;

+

+		case MqttsMessage.WILLMSGREQ:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.WILLMSG:

+			handleMqttsWillMsg((MqttsWillMsg) receivedMsg);

+			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:

+			handleMqttsSubscribe((MqttsSubscribe) receivedMsg);

+			break;

+

+		case MqttsMessage.SUBACK:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.UNSUBSCRIBE:

+			handleMqttsUnsubscribe((MqttsUnsubscribe) receivedMsg);

+			break;

+

+		case MqttsMessage.UNSUBACK:

+			//we will never receive such a message from the client

+			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:

+			handleMqttsWillTopicUpd((MqttsWillTopicUpd) receivedMsg);

+			break;

+

+		case MqttsMessage.WILLTOPICRESP:

+			//we will never receive such a message from the client

+			break;

+

+		case MqttsMessage.WILLMSGUPD:

+			handleMqttsWillMsgUpd((MqttsWillMsgUpd) receivedMsg);

+			break;

+

+		case MqttsMessage.WILLMSGRESP:

+			//we will never receive such a message from the client

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}	

+

+

+	/**

+	 * The method that handles a Mqtts SEARCHGW message.

+	 *  

+	 * @param receivedMsg The received MqttsSearchGW message.

+	 */

+	private void handleMqttsSearchGW(MqttsSearchGW receivedMsg) {		

+		//		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts SEARCHGW message with \"Radius\" = \""+receivedMsg.getRadius()+"\" received. The message will be handled by GatewayMsgHandler.");

+

+		//construct an "internal" message (see org.eclipse.paho.mqttsn.gateway.messages.Message)

+		//for the GatewayMsgHandler and put it to the dispatcher's queue 

+		GatewayAddress gwAddress = GWParameters.getGatewayAddress();

+		Message msg = new Message(gwAddress);

+

+		msg.setType(Message.MQTTS_MSG);

+		msg.setMqttsMessage(receivedMsg);

+		dispatcher.putMessage(msg);

+	}

+

+

+	/**

+	 * The method that handles a Mqtts CONNECT message.

+	 * 

+	 * @param receivedMsg The received MqttsConnect message.

+	 */

+	private void handleMqttsConnect(MqttsConnect receivedMsg) {		

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts CONNECT message with \"Will\" = \"" +receivedMsg.isWill()+"\" and \"CleanSession\" = \"" +receivedMsg.isCleanSession()+"\" received.");

+

+		this.clientId = receivedMsg.getClientId();

+		brokerInterface.setClientId(clientId);

+

+		//if the client is already connected return a Mqtts CONNACK 

+		if(client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is already connected. Mqtts CONNACK message will be send to the client.");

+			MqttsConnack connack = new MqttsConnack();

+			connack.setReturnCode(MqttsMessage.RETURN_CODE_ACCEPTED);

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts CONNACK message to the client.");

+			clientInterface.sendMsg(this.clientAddress, connack);	

+			return;

+		}

+

+		//if the gateway is already in process of establishing a connection with the client, drop the message 

+		if(gateway.isEstablishingConnection()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is already establishing a connection. The received Mqtts CONNECT message cannot be processed.");

+			return;

+		}

+

+		//if the will flag of the Mqtts CONNECT message is not set, 

+		//construct a Mqtt CONNECT message, send it to the broker and return

+		if(!receivedMsg.isWill()){			

+			MqttConnect mqttConnect = new MqttConnect();

+			mqttConnect.setProtocolName(receivedMsg.getProtocolName());

+			mqttConnect.setProtocolVersion (receivedMsg.getProtocolVersion());

+			mqttConnect.setWill (receivedMsg.isWill());	

+			mqttConnect.setCleanStart (receivedMsg.isCleanSession());

+			mqttConnect.setKeepAlive(receivedMsg.getDuration());

+			mqttConnect.setClientId (receivedMsg.getClientId());

+

+			//open a new TCP/IP connection with the broker 

+			try {

+				brokerInterface.initialize();

+			} catch (MqttsException e) {

+				e.printStackTrace();

+				GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - An error occurred while TCP/IP connection setup with the broker.");

+				return;

+			}

+

+			//send the Mqtt CONNECT message to the broker

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt CONNECT message to the broker.");

+			try {

+				brokerInterface.sendMsg(mqttConnect);

+			} catch (MqttsException e) {

+				e.printStackTrace();

+				GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt CONNECT message to the broker.");

+				return;

+			}

+

+			//set the state of the client as "Connected"

+			client.setConnected();

+			return;

+		}

+

+		//if the will flag is set, store the received Mqtts CONNECT message, construct a 

+		//Mqtts WILTOPICREQ message, and send it to the client

+		this.mqttsConnect = receivedMsg;

+		MqttsWillTopicReq willTopicReq = new MqttsWillTopicReq();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts WILLTOPICREQ message to the client.");

+		clientInterface.sendMsg(this.clientAddress, willTopicReq);

+

+		//set the gateway on "waitingWillTopic" state and increase 

+		//the tries of sending Mqtts WILLTOPICREQ message to the client

+		gateway.setWaitingWillTopic();

+		gateway.increaseTriesSendingWillTopicReq();

+

+		//set a timeout for waiting a Mqtts WILLTOPIC message from the client by registering to the timer

+		timer.register(this.clientAddress, ControlMessage.WAITING_WILLTOPIC_TIMEOUT, GWParameters.getWaitingTime());

+	}

+

+

+	/**

+	 * The method that handles a Mqtts WILLTOPIC message.

+	 * 

+	 * @param receivedMsg The received MqttsWillTopic message.

+	 */

+	private void handleMqttsWillTopic(MqttsWillTopic receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts WILLTOPIC message with \"WillTopic\" = \""+receivedMsg.getWillTopic()+"\" received.");

+		//if the gateway is not expecting a Mqtts WILLTOPIC at this time, drop the received message and return

+		if(!gateway.isWaitingWillTopic()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtts WILLTOPIC message from the client. The received message cannot be processed.");

+			return;

+		}

+

+		//"reset" the "waitingWillTopic" state of the gateway, "reset" the tries of sending 

+		//Mqtts WILLTOPICREQ message to the client and unregister from the timer

+		gateway.resetWaitingWillTopic();

+		gateway.resetTriesSendingWillTopicReq();

+		timer.unregister(this.clientAddress,ControlMessage.WAITING_WILLTOPIC_TIMEOUT);

+

+		//store the received Mqtts WILLTOPIC message, construct a Mqtts 

+		//WILLMSGREQ message, and send it to the client

+		this.mqttsWillTopic = receivedMsg;

+		MqttsWillMsgReq willMsgReq = new MqttsWillMsgReq();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts WILLMSGREQ message to the client.");

+		clientInterface.sendMsg(this.clientAddress, willMsgReq);

+

+		//set the gateway on "waitingWillMsg" state and increase 

+		//the tries of sending Mqtts WILLMSGREQ message to the client

+		gateway.setWaitingWillMsg();

+		gateway.increaseTriesSendingWillMsgReq();

+

+		//set a timeout for waiting a Mqtts WILLMSG message from the client by registering to the timer

+		timer.register(this.clientAddress, ControlMessage.WAITING_WILLMSG_TIMEOUT, GWParameters.getWaitingTime());

+	}

+

+	/**

+	 * The method that handles a Mqtts WILLMSG message.

+	 * 

+	 * @param receivedMsg The received MqttsWillMsg message.

+	 */

+	private void handleMqttsWillMsg(MqttsWillMsg receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts WILLMSG message with \"WillMsg\" = \""+receivedMsg.getWillMsg()+"\" received.");

+		//if the gateway is not expecting a Mqtts WILLMSG at this time, drop the received message and return

+		if(!gateway.isWaitingWillMsg()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtts WILLMSG message from the client.The received message cannot be processed.");

+			return;

+		}

+

+		//"reset" the "waitingWillMsg" state of the gateway, "reset" the tries of sending 

+		//Mqtts WILLMSGREQ message to the client and unregister from the timer

+		gateway.resetWaitingWillMsg();

+		gateway.resetTriesSendingWillMsgReq();

+		timer.unregister(this.clientAddress, ControlMessage.WAITING_WILLMSG_TIMEOUT);

+

+		//assure that the stored Mqtts CONNECT and Mqtts WILLTOPIC messages that we received before are not null

+		//if one of them is null delete the other and return (debugging checks)

+		if (this.mqttsConnect == null){				

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts CONNECT message is null. The received Mqtts WILLMSG message cannot be processed.");

+			this.mqttsWillTopic = null;

+			return;

+		}

+		if (this.mqttsWillTopic == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts WILLTOPIC message is null. The received Mqtts WILLMSG message cannot be processed.");

+			this.mqttsConnect = null;

+			return;

+		}

+

+		//construct a Mqtt CONNECT message		

+		MqttConnect mqttConnect = new MqttConnect();

+

+		//populate the Mqtt CONNECT message with the information of the stored Mqtts CONNECT

+		//and WILLTOPIC messages and the information of the received Mqtts WILLMSG message 

+		mqttConnect.setProtocolName(this.mqttsConnect.getProtocolName());

+		mqttConnect.setProtocolVersion (this.mqttsConnect.getProtocolVersion());

+		mqttConnect.setWillRetain (this.mqttsWillTopic.isRetain());

+		mqttConnect.setWillQoS (this.mqttsWillTopic.getQos());

+		mqttConnect.setWill (this.mqttsConnect.isWill());	

+		mqttConnect.setCleanStart (this.mqttsConnect.isCleanSession());

+		mqttConnect.setKeepAlive(this.mqttsConnect.getDuration());

+		mqttConnect.setClientId (this.mqttsConnect.getClientId());

+		mqttConnect.setWillTopic (this.mqttsWillTopic.getWillTopic());

+		mqttConnect.setWillMessage (receivedMsg.getWillMsg());

+

+		//open a new TCP/IP connection with the broker 

+		try {

+			brokerInterface.initialize();

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - An error occurred while TCP/IP connection setup with the broker.");

+			return;

+		}

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt CONNECT message to the broker.");

+		//send the Mqtt CONNECT message to the broker

+		try {

+			brokerInterface.sendMsg(mqttConnect);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt CONNECT message to the broker.");

+			return;

+		}

+

+		//set the state of the client as "Connected"

+		client.setConnected();

+

+		//delete the stored Mqtts CONNECT and Mqtts WILLTOPIC messages

+		this.mqttsConnect = null;

+		this.mqttsWillTopic = null;

+	}

+

+

+	/**

+	 * The method that handles a Mqtts REGISTER message.

+	 * 

+	 * @param receivedMsg The received MqttsRegister message.

+	 */

+	private void handleMqttsRegister(MqttsRegister receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts REGISTER message with \"TopicName\" = \"" +receivedMsg.getTopicName()+"\" received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts REGISTER message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		int topicId = topicIdMappingTable.getTopicId(receivedMsg.getTopicName());

+		if (topicId == 0){				

+			//assign a topicID to the received topicName

+			topicId = getNewTopicId();

+			topicIdMappingTable.assignTopicId(topicId, receivedMsg.getTopicName());

+		}

+

+		//construct a Mqtts REGACK message

+		MqttsRegack regack = new MqttsRegack();

+		regack.setTopicId(topicId);

+		regack.setMsgId(receivedMsg.getMsgId());

+		regack.setReturnCode(MqttsMessage.RETURN_CODE_ACCEPTED);

+

+		//send the Mqtts REGACK message to the client	

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts REGACK message with \"TopicId\" = \"" +topicId+"\" to the client.");

+		clientInterface.sendMsg(this.clientAddress, regack);

+	}

+

+	/**

+	 * The method that handles a Mqtts REGACK message.

+	 * 

+	 * @param receivedMsg The received MqttsRegack message.

+	 */

+	private void handleMqttsRegack(MqttsRegack receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts REGACK message with \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts REGACK message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//if the gateway is not expecting a Mqtts REGACK at this time, drop the received message and return

+		if(!gateway.isWaitingRegack()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtts REGACK message from the client. The received message cannot be processed.");

+			return;

+		}

+

+		//assure that the stored Mqtts REGISTER and Mqtt PUBLISH messages are not null

+		//if one of them is null delete the other and return (debugging checks)

+		if (this.mqttsRegister == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts REGISTER message is null. The received Mqtts REGACK message cannot be processed.");

+

+			//"reset" the "waitingRegack" state of the gateway, "reset" the tries of sending 

+			//Mqtts REGISTER message to the client and unregister from the timer

+			gateway.resetWaitingRegack();

+			gateway.resetTriesSendingRegister();

+			timer.unregister(this.clientAddress, ControlMessage.WAITING_REGACK_TIMEOUT);

+

+			this.mqttPublish = null;

+			return;

+		}

+		if (this.mqttPublish == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtt PUBLISH message is null. The received Mqtts REGACK message cannot be processed.");

+

+			//"reset" the "waitingRegack" state of the gateway, "reset" the tries of sending 

+			//Mqtts REGISTER message to the client and unregister from the timer

+			gateway.resetWaitingRegack();

+			gateway.resetTriesSendingRegister();

+			timer.unregister(this.clientAddress, ControlMessage.WAITING_REGACK_TIMEOUT);

+

+			this.mqttsRegister = null;

+			return;

+		}

+

+		//if the MsgId of the received Mqtt REGACK is not the same with MsgId of the stored Mqtts 

+		//REGISTER message drop the received message and return (don't delete any stored message)

+		if(receivedMsg.getMsgId() != this.mqttsRegister.getMsgId()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts REGACK message does not match the MsgId (\""+this.mqttsRegister.getMsgId()+"\") of the stored Mqtts REGISTER message. The message cannot be processed.");

+			return;

+		}

+

+		//assign the topicId of the Mqtts REGACK message to the received topicName of 

+		//the Mqtt PUBLISH message (topicId is the same as in the stored Mqtts REGISTER message)

+

+		topicIdMappingTable.assignTopicId(receivedMsg.getTopicId(), this.mqttPublish.getTopicName());

+

+		//now we have a topicId, so construct a Mqtts PUBLISH message

+		MqttsPublish publish = new MqttsPublish();

+

+		//populate the Mqtts PUBLISH message with the information of the stored Mqtt PUBLISH message

+		publish.setDup(mqttPublish.isDup());

+		publish.setQos(mqttPublish.getQos());

+		publish.setRetain(mqttPublish.isRetain());

+		publish.setTopicIdType(MqttsMessage.NORMAL_TOPIC_ID);

+		publish.setTopicId(receivedMsg.getTopicId());

+		publish.setMsgId(mqttPublish.getMsgId());

+		publish.setData(mqttPublish.getPayload());

+

+		//send the Mqtts PUBLISH message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBLISH message with \"QoS\" = \""+mqttPublish.getQos()+"\" and \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" to the client.");

+		clientInterface.sendMsg(this.clientAddress, publish);

+

+		//"reset" the "waitingRegack" state of the gateway, "reset" the tries of sending 

+		//Mqtts REGISTER message to the client, unregister from the timer and delete

+		//the stored Mqtts REGISTER and Mqtt PUBLISH messages		

+		gateway.resetWaitingRegack();

+		gateway.resetTriesSendingRegister();

+		timer.unregister(this.clientAddress, ControlMessage.WAITING_REGACK_TIMEOUT);

+		this.mqttsRegister = null;

+		this.mqttPublish = null;		

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PUBLISH message.

+	 * 

+	 * @param receivedMsg The received MqttsPublish message.

+	 */

+	private void handleMqttsPublish(MqttsPublish receivedMsg) {

+		if(receivedMsg.getTopicIdType() == MqttsMessage.NORMAL_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getTopicId()+"\" received.");

+		else if (receivedMsg.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getTopicId()+"\" (predefined topid Id) received.");

+		else if (receivedMsg.getTopicIdType() == MqttsMessage.SHORT_TOPIC_NAME)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getShortTopicName()+"\" (short topic name) received.");

+		else{

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\") received. The message cannot be processed.");

+			return;

+		}

+

+

+		//if Mqtts PUBLISH message has QoS = -1, construct an "internal" message (see org.eclipse.paho.mqttsn.gateway.core.Message)

+		//for the GatewayMsgHandler and put it to the dispatcher's queue 

+		if(receivedMsg.getQos()== -1){

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The received Mqtts PUBLISH message with \"QoS\" = \"-1\" will be handled by GatewayMsgHandler.");

+

+			Message msg = new Message(GWParameters.getGatewayAddress());

+

+			msg.setType(Message.MQTTS_MSG);

+			msg.setMqttsMessage(receivedMsg);

+			dispatcher.putMessage(msg);

+			return;

+		}

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PUBLISH message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//if there is already a publish procedure from the client with QoS 1 and the 

+		//gateway is expecting a Mqtt PUBACK from the broker, then drop the message if it has QoS 1 

+		if(gateway.isWaitingPuback() && receivedMsg.getQos() == 1){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is already in a publish procedure with \"QoS\" = \"1\". The received Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" cannot be processed.");

+			return;

+		}

+

+		//else construct a Mqtt PUBLISH message

+		MqttPublish publish = new MqttPublish();

+

+		//check the TopicIdType in the received Mqtts PUBLISH message

+		switch(receivedMsg.getTopicIdType()){

+

+		//if the TopicIdType is a normal TopicId

+		case MqttsMessage.NORMAL_TOPIC_ID:

+			if(receivedMsg.getTopicId() <= GWParameters.getPredfTopicIdSize()){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - TopicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message is in the range of predefined topic Ids [1,"+GWParameters.getPredfTopicIdSize()+"]. The message cannot be processed. Mqtts PUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts PUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsPuback puback = new MqttsPuback();

+				puback.setTopicId(receivedMsg.getTopicId());

+				puback.setMsgId(receivedMsg.getMsgId());

+				puback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts PUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+				clientInterface.sendMsg(this.clientAddress, puback);

+				return;

+			}

+

+			//get the TopicName by TopicId

+			String topicName = topicIdMappingTable.getTopicName(receivedMsg.getTopicId());

+

+			//if there is no such an entry

+			if(topicName == null){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - TopicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message does not exist. The message cannot be processed. Mqtts PUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts PUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsPuback puback = new MqttsPuback();

+				puback.setTopicId(receivedMsg.getTopicId());

+				puback.setMsgId(receivedMsg.getMsgId());

+				puback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts PUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+				clientInterface.sendMsg(this.clientAddress, puback);

+				return;

+			}

+

+			//we found a topicName corresponding to the received topicId

+			publish.setTopicName(topicName);				

+			break;

+

+			//if the TopicIdType is a shortTopicName then simply copy it to the topicName field of the Mqtt PUBLISH message

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			publish.setTopicName(receivedMsg.getShortTopicName());	

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			if(receivedMsg.getTopicId() > GWParameters.getPredfTopicIdSize()){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message is out of the range of predefined topic Ids [1,"+GWParameters.getPredfTopicIdSize()+"]. The message cannot be processed. Mqtts PUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts PUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsPuback puback = new MqttsPuback();

+				puback.setTopicId(receivedMsg.getTopicId());

+				puback.setMsgId(receivedMsg.getMsgId());

+				puback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts PUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+				clientInterface.sendMsg(this.clientAddress, puback);

+				return;

+			}

+

+			//get the predefined topic name that corresponds to the received predefined topicId

+			topicName = topicIdMappingTable.getTopicName(receivedMsg.getTopicId());

+

+			//this should not happen as predefined topic ids are already stored

+			if(topicName == null){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message does not exist. The message cannot be processed. Mqtts PUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts PUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsPuback puback = new MqttsPuback();

+				puback.setTopicId(receivedMsg.getTopicId());

+				puback.setMsgId(receivedMsg.getMsgId());

+				puback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts PUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" +receivedMsg.getTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+				clientInterface.sendMsg(this.clientAddress, puback);

+				return;

+			}

+

+			publish.setTopicName(topicName);

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\"). The received Mqtts PUBLISH message cannot be processed.");

+			return;	

+		}

+

+		//populate the Mqtt PUBLISH message with the remaining information from Mqtts PUBLISH message

+		publish.setDup(receivedMsg.isDup());

+		publish.setQos(receivedMsg.getQos());

+		publish.setRetain(receivedMsg.isRetain());

+		publish.setMsgId(receivedMsg.getMsgId());

+		publish.setPayload(receivedMsg.getData());		

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicName\" = \""+publish.getTopicName()+ "\" to the broker.");

+		//send the Mqtt PUBLISH message to the broker

+		try {

+			brokerInterface.sendMsg(publish);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBLISH message to the broker.");

+			connectionLost();

+			return;

+		}

+

+		//TODO handle qos 2

+		if(receivedMsg.getQos() == 1){

+			gateway.setWaitingPuback();

+			this.mqttsPublish = receivedMsg;

+		}

+		//if(receivedMsg.getQos() == 2)				

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PUBACK message.

+	 * 

+	 * @param receivedMsg The received MqttsPuback message.

+	 */

+	private void handleMqttsPuback(MqttsPuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBACK message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PUBACK message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//if the return code of the Mqtts PUBACK message is "Rejected: Invalid topic ID", then

+		//delete this topicId(and the associate topic name)from the mapping table 

+		if(receivedMsg.getReturnCode() == MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The received Mqtts PUBACK has \"ReturnCode\" = \"Rejected: invalid TopicId\". TopicId \"" +receivedMsg.getTopicId()+"\" will be deleted from mapping table.");

+			topicIdMappingTable.removeTopicId(receivedMsg.getTopicId());

+			return;

+		}

+

+		//else if everything is ok, construct a Mqtt PUBACK message  

+		MqttPuback puback = new MqttPuback();

+		puback.setMsgId(receivedMsg.getMsgId());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBACK message to the broker.");

+		//send the Mqtt PUBACK message to the broker

+		try {

+			brokerInterface.sendMsg(puback);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBACK message to the broker.");

+			connectionLost();

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PUBCOMP message.

+	 * 

+	 * @param receivedMsg The received MqttsPubComp message.

+	 */

+	private void handleMqttsPubComp(MqttsPubComp receivedMsg) {	

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBCOMP message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PUBCOMP message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//else construct a Mqtt PUBCOMP message

+		MqttPubComp pubcomp = new MqttPubComp();

+		pubcomp.setMsgId(receivedMsg.getMsgId());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBCOMP message to the broker.");

+		//send the Mqtt PUBCOMP message to the broker

+		try {

+			brokerInterface.sendMsg(pubcomp);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBCOMP message to the broker.");

+			connectionLost();

+		}	

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PUBREC message.

+	 * 

+	 * @param receivedMsg The received MqttsPubRec message.

+	 */

+	private void handleMqttsPubRec(MqttsPubRec receivedMsg) {		

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBREC message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PUBREC message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//construct a Mqtt PUBREC message

+		MqttPubRec pubrec = new MqttPubRec();

+		pubrec.setMsgId(receivedMsg.getMsgId());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBREC message to the broker.");

+		//send the Mqtt PUBREC message to the broker	

+		try {

+			brokerInterface.sendMsg(pubrec);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBREC message to the broker.");

+			connectionLost();

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PUBREL message.

+	 * 

+	 * @param receivedMsg The received MqttsPubRel message.

+	 */

+	private void handleMqttsPubRel(MqttsPubRel receivedMsg) {		

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBREL message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PUBREL message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//construct a Mqtt PUBREL message

+		MqttPubRel pubrel = new MqttPubRel();

+		pubrel.setMsgId(receivedMsg.getMsgId());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBREL message to the broker.");

+		//send the Mqtt PUBREL message to the broker

+		try {

+			brokerInterface.sendMsg(pubrel);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBREL message to the broker.");

+			connectionLost();

+		}		

+	}

+

+

+	/**

+	 * The method that handles a Mqtts SUBSCRIBE message.

+	 * 

+	 * @param receivedMsg The received MqttsSubscribe message.

+	 */

+	private void handleMqttsSubscribe(MqttsSubscribe receivedMsg) {

+		if(receivedMsg.getTopicIdType() == MqttsMessage.TOPIC_NAME)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts SUBSCRIBE message with \"TopicName\" = \""+receivedMsg.getTopicName()+"\" received.");

+		else if(receivedMsg.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts SUBSCRIBE message with \"TopicId\" = \""+receivedMsg.getPredefinedTopicId()+"\" (predefined topid Id) received.");

+		else if(receivedMsg.getTopicIdType() == MqttsMessage.SHORT_TOPIC_NAME)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts SUBSCRIBE message with \"TopicId\" = \""+receivedMsg.getShortTopicName()+"\" (short topic name) received.");

+		else{

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts SUBSCRIBE message with unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\") received. The message cannot be processed.");

+			return;

+		}

+

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts SUBSCRIBE message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//if we are already in a subscription process, drop the received message and return

+		if(gateway.isWaitingSuback()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is already in a subscription procedure. The received Mqtts SUBSCRIBE message cannot be processed.");

+			return;

+		}

+

+		//else construct a Mqtt SUBSCRIBE message

+		MqttSubscribe mqttSubscribe = new MqttSubscribe(); 

+

+		//check the TopicIdType in the received Mqtts SUBSCRIBE message

+		switch(receivedMsg.getTopicIdType()){

+

+		//if the TopicIdType is a TopicName

+		case MqttsMessage.TOPIC_NAME:

+			mqttSubscribe.setTopicName(receivedMsg.getTopicName());

+			break;

+

+			//if the TopicIdType is a shortTopicName 

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			mqttSubscribe.setTopicName(receivedMsg.getShortTopicName());	

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			if(receivedMsg.getPredefinedTopicId() > GWParameters.getPredfTopicIdSize()){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + + receivedMsg.getPredefinedTopicId() + "\") of the received Mqtts SUBSCRIBE message is out of the range of predefined topic Ids [1,"+GWParameters.getPredfTopicIdSize()+"]. The message cannot be processed. Mqtts SUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts SUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsSuback suback = new MqttsSuback();

+				suback.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);

+				suback.setPredefinedTopicId(receivedMsg.getPredefinedTopicId());

+				suback.setMsgId(receivedMsg.getMsgId());

+				suback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts SUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts SUBACK message with \"TopicId\" = \"" +receivedMsg.getPredefinedTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+

+				clientInterface.sendMsg(this.clientAddress, suback);			

+

+				return;

+			}

+

+			//get the predefined topic name that corresponds to the predefined topicId

+			String topicName = topicIdMappingTable.getTopicName(receivedMsg.getPredefinedTopicId());

+

+			//this should not happen as predefined topic ids are already stored

+			if(topicName == null){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + receivedMsg.getPredefinedTopicId() + "\") of the received Mqtts SUBSCRIBE message does not exist. The message cannot be processed. Mqtts SUBACK with rejection reason will be sent to the client.");

+

+				//construct a Mqtts SUBACK message with ReturnCode = "Rejected:Invalid TopicId"

+				MqttsSuback suback = new MqttsSuback();

+				suback.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);

+				suback.setPredefinedTopicId(receivedMsg.getPredefinedTopicId());

+				suback.setMsgId(receivedMsg.getMsgId());

+				suback.setReturnCode(MqttsMessage.RETURN_CODE_INVALID_TOPIC_ID);

+

+				//send the Mqtts SUBACK message to the client	

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts SUBACK message with \"TopicId\" = \"" +receivedMsg.getPredefinedTopicId()+"\" and \"ReturnCode\" = \"Rejected: invalid TopicId\" to the client.");

+

+				clientInterface.sendMsg(this.clientAddress, suback);					

+				return;

+			}

+			mqttSubscribe.setTopicName(topicName);

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\"). The received Mqtts SUBSCRIBE message cannot be processed.");

+			return;				

+		}

+

+		//store the received Mqtts SUBSCRIBE message (for handling Mqtt SUBACK from the broker)

+		this.mqttsSubscribe = receivedMsg;

+

+		// populate the Mqtt SUBSCRIBE message with the remaining information from Mqtts SUBSCRIBE message

+		mqttSubscribe.setDup(receivedMsg.isDup());

+

+		mqttSubscribe.setMsgId(receivedMsg.getMsgId());

+

+		//set the requested QoS for the specific topic name

+		mqttSubscribe.setRequestedQoS(receivedMsg.getQos());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt SUBSCRIBE message with \"TopicName\" = \""+mqttSubscribe.getTopicName()+ "\" to the broker.");

+		//send the Mqtt SUBSCRIBE message to the broker

+		try {

+			brokerInterface.sendMsg(mqttSubscribe);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt SUBSCRIBE message to the broker.");

+			connectionLost();

+			return;

+		}

+

+		//set the gateway on "waitingSuback" state 

+		gateway.setWaitingSuback();

+	}

+

+

+	/**

+	 * The method that handles a Mqtts UNSUBSCRIBE message.

+	 * 

+	 * @param receivedMsg The received MqttsUnsubscribe message.

+	 */

+	private void handleMqttsUnsubscribe(MqttsUnsubscribe receivedMsg) {				

+		if(receivedMsg.getTopicIdType() == MqttsMessage.TOPIC_NAME)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts UNSUBSCRIBE message with \"TopicName\" = \""+receivedMsg.getTopicName()+"\" received.");

+		else if(receivedMsg.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts UNSUBSCRIBE message with \"TopicId\" = \""+receivedMsg.getPredefinedTopicId()+"\" (predefined topid Id) received.");

+		else if(receivedMsg.getTopicIdType() == MqttsMessage.SHORT_TOPIC_NAME)

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts UNSUBSCRIBE message with \"TopicId\" = \""+receivedMsg.getShortTopicName()+"\" (short topic name) received.");

+		else{

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts UNSUBSCRIBE message with unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\") received. The message cannot be processed.");

+			return;

+		}

+

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts UNSUBSCRIBE message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//if we are already in an un-subscription process, drop the received message and return

+		if(gateway.isWaitingUnsuback()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is already in a un-subscription procedure. The received Mqtts UNSUBSCRIBE message cannot be processed.");

+			return;

+		}

+

+		//else construct a Mqtt UNSUBSCRIBE message

+		MqttUnsubscribe mqttUnsubscribe = new MqttUnsubscribe(); 

+

+		//check the TopicIdType in the received Mqtts UNSUBSCRIBE message

+		switch(receivedMsg.getTopicIdType()){

+

+		//if the TopicIdType is a TopicName

+		case MqttsMessage.TOPIC_NAME:

+			mqttUnsubscribe.setTopicName(receivedMsg.getTopicName());

+			break;

+

+			//if the TopicIdType is a shortTopicName 

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			mqttUnsubscribe.setTopicName(receivedMsg.getShortTopicName());	

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			if(receivedMsg.getPredefinedTopicId() > GWParameters.getPredfTopicIdSize()){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + + receivedMsg.getPredefinedTopicId() + "\") of the received Mqtts UNSUBSCRIBE message is out of the range of predefined topic Ids [1,"+GWParameters.getPredfTopicIdSize()+"]. The message cannot be processed.");

+				return;

+			}				

+

+			String topicName = topicIdMappingTable.getTopicName(receivedMsg.getPredefinedTopicId());

+

+			//this should not happen

+			if(topicName == null){

+				GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + + receivedMsg.getPredefinedTopicId() + "\") does not exist. The received Mqtts UNSUBSCRIBE message cannot be processed.");

+				return;

+			}

+			mqttUnsubscribe.setTopicName(topicName);

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\"). The received Mqtts UNSUBSCRIBE message cannot be processed.");

+			return;				

+		}

+

+		//store the received Mqtts UNSUBSCRIBE message (for handling Mqtt UNSUBACK)

+		this.mqttsUnsubscribe = receivedMsg;

+

+		// populate the Mqtt UNSUBSCRIBE message with the remaining information from Mqtts UNSUBSCRIBE message

+		mqttUnsubscribe.setDup(receivedMsg.isDup());

+

+		mqttUnsubscribe.setMsgId(receivedMsg.getMsgId());

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt UNSUBSCRIBE message with \"TopicName\" = \""+mqttUnsubscribe.getTopicName()+ "\" to the broker.");

+		//send the Mqtt UNSUBSCRIBE message to the broker

+		try {

+			brokerInterface.sendMsg(mqttUnsubscribe);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt UNSUBSCRIBE message to the broker.");

+			connectionLost();

+			return;

+		}

+

+		//set the gateway on "waitingUnsuback" state 

+		gateway.setWaitingUnsuback();

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PINGREQ message.

+	 * 

+	 * @param receivedMsg The received MqttsPingReq message.

+	 */

+	private void handleMqttsPingReq(MqttsPingReq receivedMsg) {		

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PINGREQ message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PINGREQ message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//construct a Mqtt PINGREQ message

+		MqttPingReq pingreq = new MqttPingReq();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PINGREQ message to the broker.");

+		//send the Mqtt PINGREQ message to the broker

+		try {

+			brokerInterface.sendMsg(pingreq);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PINGREQ message to the broker.");

+			connectionLost();		

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtts PINGRESP message.

+	 * 

+	 * @param receivedMsg The received MqttsPingResp message.

+	 */

+	private void handleMqttsPingResp(MqttsPingResp receivedMsg) {		

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts PINGRESP message received.");

+

+		//if the client is not in state "Connected" send to it a Mqtts DISCONNECT message and return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts PINGRESP message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//construct a Mqtt PINGRESP message

+		MqttPingResp pingresp = new MqttPingResp();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PINGRESP message to the broker.");

+		//send the Mqtt PINGRESP message to the broker

+		try {

+			brokerInterface.sendMsg(pingresp);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			//if failed sending the message

+			GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Failed sending Mqtt PINGRESP message to the broker.");

+			connectionLost();

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtts DISCONNECT message.

+	 * 

+	 * @param receivedMsg The received MqttsDisconnect message.

+	 */

+	private void handleMqttsDisconnect(MqttsDisconnect receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts DISCONNECT message received.");

+

+		//if the client is not in state "Connected" return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtts DISCONNECT message cannot be processed.");

+			return;

+		}

+

+		//else, stop the reading thread of the BrokerInterface

+		//(this does not have any effect to the input and output streams which remain active)

+		brokerInterface.setRunning(false);

+

+		//construct a Mqtt DISCONNECT message

+		MqttDisconnect mqttDisconnect = new MqttDisconnect();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt DISCONNECT message to the broker.");

+		//send the Mqtt DISCONNECT message to the broker

+		//(no checks - don't bother if the sending of Mqtt DISCONNECT message to the broker was successful or not)

+		try {

+			brokerInterface.sendMsg(mqttDisconnect);

+		} catch (MqttsException e) {

+			//do nothing

+		}		

+

+		//call sendClientDisconnect method of this handler

+		sendClientDisconnect();

+	}

+

+

+	/**

+	 * The method that handles a Mqtts WILLTOPICUPD message.

+	 * 

+	 * @param receivedMsg The received MqttsWillTopicUpd message.

+	 */

+	private void handleMqttsWillTopicUpd(MqttsWillTopicUpd receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts WILLTOPICUPD message received.");

+	}

+

+

+	/**

+	 * The method that handles a Mqtts WILLMSGUPD message.

+	 * 

+	 * @param receivedMsg The received MqttsWillMsgUpd message.

+	 */

+	private void handleMqttsWillMsgUpd(MqttsWillMsgUpd receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtts WILLMSGUPD received.");

+	}

+

+

+

+	/******************************************************************************************/

+	/**                      HANDLING OF MQTT MESSAGES FROM THE BROKER                      **/

+	/****************************************************************************************/

+

+	/* (non-Javadoc)

+	 * @see org.eclipse.paho.mqttsn.gateway.core.MsgHandler#handleMqttMessage(org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage)

+	 */

+	public void handleMqttMessage(MqttMessage receivedMsg){

+		//update this handler's timeout

+		timeout = System.currentTimeMillis() + GWParameters.getHandlerTimeout()*1000;

+

+		//get the type of the Mqtt message and handle the message according to that type	

+		switch(receivedMsg.getMsgType()){

+		case MqttMessage.CONNECT:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.CONNACK:

+			handleMqttConnack((MqttConnack) receivedMsg);

+			break;

+

+		case MqttMessage.PUBLISH:

+			handleMqttPublish((MqttPublish) receivedMsg);

+			break;

+

+		case MqttMessage.PUBACK:

+			handleMqttPuback((MqttPuback)receivedMsg);

+			break;

+

+		case MqttMessage.PUBREC:

+			handleMqttPubRec((MqttPubRec) receivedMsg);

+			break;

+

+		case MqttMessage.PUBREL:

+			handleMqttPubRel((MqttPubRel)receivedMsg);

+			break;

+

+		case MqttMessage.PUBCOMP:

+			handleMqttPubComp((MqttPubComp) receivedMsg);

+			break;

+

+		case MqttMessage.SUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.SUBACK:

+			handleMqttSuback((MqttSuback) receivedMsg);

+			break;

+

+		case MqttMessage.UNSUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.UNSUBACK:

+			handleMqttUnsuback((MqttUnsuback) receivedMsg);

+			break;

+

+		case MqttMessage.PINGREQ:

+			handleMqttPingReq((MqttPingReq) receivedMsg);

+			break;

+

+		case MqttMessage.PINGRESP:

+			handleMqttPingResp((MqttPingResp) receivedMsg);

+			break;

+

+		case MqttMessage.DISCONNECT:

+			//we will never receive such a message from the broker

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtt CONNACK message.

+	 * 

+	 * @param receivedMsg The received MqttConnack message.

+	 */

+	private void handleMqttConnack(MqttConnack receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt CONNACK message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt CONNACK message cannot be processed.");

+			return;

+		}

+

+		//if the return code of the Mqtt CONNACK message is not "Connection Accepted", drop the message

+		if (receivedMsg.getReturnCode() != MqttMessage.RETURN_CODE_CONNECTION_ACCEPTED){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Return Code of Mqtt CONNACK message it is not \"Connection Accepted\". The received Mqtt CONNACK message cannot be processed.");

+			sendClientDisconnect();

+			return;

+		}

+

+		//else construct a Mqtts CONNACK message

+		MqttsConnack msg = new MqttsConnack();

+		msg.setReturnCode(MqttsMessage.RETURN_CODE_ACCEPTED);

+

+		//send the Mqtts CONNACK message to the client	

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts CONNACK message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);	

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PUBLISH message.

+	 * 

+	 * @param receivedMsg The received MqttPublish message

+	 */

+	private void handleMqttPublish(MqttPublish receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+ "\" and \"TopicName\" = \""+receivedMsg.getTopicName()+"\" received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PUBLISH message cannot be processed.");

+			return;

+		}

+

+		//if the data is too long to fit into a Mqtts PUBLISH message or the topic name is too

+		//long to fit into a Mqtts REGISTER message then drop the received message 

+		if (receivedMsg.getPayload().length > GWParameters.getMaxMqttsLength() - 7){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The payload in the received Mqtt PUBLISH message does not fit into a Mqtts PUBLISH message (payload length = "+receivedMsg.getPayload().length+ ". The message cannot be processed.");

+			return;

+		}

+

+		if (receivedMsg.getTopicName().length() > GWParameters.getMaxMqttsLength() - 6){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The topic name in the received Mqtt PUBLISH message does not fit into a Mqtts REGISTER message (topic name length = "+receivedMsg.getTopicName().length()+ ". The message cannot be processed.");

+			return;

+		}

+

+

+		//get the corresponding topicId from the topicName of the Mqtt PUBLISH message		

+		int topicId = topicIdMappingTable.getTopicId(receivedMsg.getTopicName());

+

+		//construct a Mqtts PUBLISH message

+		MqttsPublish publish = new MqttsPublish();

+

+		//if topicId exists then accept the Mqtt PUBLISH and send a Mqtts PUBLISH to the client

+		if(topicId != 0){			

+			//populate the Mqtts PUBLISH message with the information from the Mqtt PUBLISH message

+			publish.setDup(receivedMsg.isDup());

+			publish.setQos(receivedMsg.getQos());

+			publish.setRetain(receivedMsg.isRetain());

+			publish.setMsgId(receivedMsg.getMsgId());

+			publish.setData(receivedMsg.getPayload());

+

+

+			//check if the retrieved topicID is associated with a normal topicName 

+			if(topicId > GWParameters.getPredfTopicIdSize()){

+				publish.setTopicIdType(MqttsMessage.NORMAL_TOPIC_ID);

+				publish.setTopicId(topicId);

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+ "\" and \"TopicId\" = \"" + topicId + "\" to the client.");

+

+			}

+			//or a predefined topic Id

+			else if (topicId>0 && topicId<=GWParameters.getPredfTopicIdSize()){

+				publish.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);

+				publish.setTopicId(topicId);

+				GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+ "\" and \"TopicId\" = \"" + topicId + "\" to the client.");

+

+			}

+			//send the Mqtts PUBLISH message to the client

+			clientInterface.sendMsg(this.clientAddress, publish);

+			return;

+		}		

+

+		//handle the case of short topic names

+		if (topicId == 0 && receivedMsg.getTopicName().length() == 2){

+			publish.setTopicIdType(MqttsMessage.SHORT_TOPIC_NAME);

+			publish.setShortTopicName(receivedMsg.getTopicName());

+			publish.setDup(receivedMsg.isDup());

+			publish.setQos(receivedMsg.getQos());

+			publish.setRetain(receivedMsg.isRetain());

+			publish.setMsgId(receivedMsg.getMsgId());

+			publish.setData(receivedMsg.getPayload());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+ "\" and \"TopicId\" = \"" + receivedMsg.getTopicName() + "\" (short topic name) to the client.");

+			return;

+		}

+

+		//if topicId doesn't exist and we are not already in a register procedure initiated by 

+		//the gateway, then store the Mqtts PUBLISH and send a Mqtts REGISTER to the client

+		if (topicId == 0 && !gateway.isWaitingRegack()){

+			//store the Mqtt PUBLISH message

+			this.mqttPublish = receivedMsg;

+

+			//get a new topicId (don't assign it until we get the REGACK message!)

+			topicId = getNewTopicId();

+

+			//construct a Mqtts REGISTER message and store it (for comparing later the MsgId)

+			this.mqttsRegister = new MqttsRegister();

+			this.mqttsRegister.setTopicId(topicId);

+			this.mqttsRegister.setMsgId(getNewMsgId());

+			this.mqttsRegister.setTopicName(receivedMsg.getTopicName());

+

+			//send the Mqtts REGISTER message to the client

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts REGISTER message with \"TopicId\" = \"" +topicId+"\"  and \"TopicName\" = \"" +receivedMsg.getTopicName()+"\" to the client.");

+			clientInterface.sendMsg(this.clientAddress, mqttsRegister);

+

+			//set the gateway on "waitingRegack" state and increase 

+			//the tries of sending Mqtts REGISTER message to the client

+			gateway.setWaitingRegack();

+			gateway.increaseTriesSendingRegister();

+

+			//set a timeout for waiting a Mqtts REGACK message from the client by registering to the timer

+			timer.register(this.clientAddress, ControlMessage.WAITING_REGACK_TIMEOUT, GWParameters.getWaitingTime());

+			return;

+		}

+

+		//if topicId doesn't exist and we are already in a register procedure initiated by 

+		//the gateway, then drop the received Mqtt PUBLISH message

+		if (topicId == 0 && gateway.isWaitingRegack()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Topic name (\"" +receivedMsg.getTopicName()+"\") does not exist in the mapping table and the gateway is waiting a Mqtts REGACK message from the client. The received Mqtt PUBLISH message cannot be processed.");

+			return;	

+		}		

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PUBACK message.

+	 * 

+	 * @param receivedMsg The received MqttPuback message.

+	 */

+	private void handleMqttPuback(MqttPuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PUBACK message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PUBACK message cannot be processed.");

+			return;

+		}		

+

+		//if the gateway is not expecting a Mqtt PUBACK at this time, drop the received message and return

+		if(!gateway.isWaitingPuback()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtt PUBACK message from the broker.The received message cannot be processed.");

+			return;

+		}

+

+		//else, assure that the stored Mqtts PUBLISH is not null (debugging checks)

+		if (this.mqttsPublish == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts PUBLISH message is null.The received Mqtt PUBACK message cannot be processed.");

+

+			//"reset" the "waitingPuback" state of the gateway

+			gateway.resetWaitingPuback();

+			return;

+		} 

+

+		//if the MsgId of the received Mqtt PUBACK is not the same with MsgId of the stored 

+		//Mqtts PUBLISH message, drop the received message and return (don't delete any stored message)

+		if(receivedMsg.getMsgId() != this.mqttsPublish.getMsgId()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Message ID of the received Mqtt PUBACK does not match the message ID of the stored Mqtts PUBLISH message.The message cannot be processed.");

+			return;

+		}		

+

+		//construct a Mqtts PUBACK message

+		MqttsPuback puback = new MqttsPuback();

+

+		puback.setMsgId(receivedMsg.getMsgId());

+		puback.setReturnCode(MqttsMessage.RETURN_CODE_ACCEPTED);

+

+

+		//check the TopicIdType in the stored Mqtts PUBLISH message

+		switch(this.mqttsPublish.getTopicIdType()){

+

+		//if the TopicIdType is a normal TopicId

+		case MqttsMessage.NORMAL_TOPIC_ID:

+			puback.setTopicId(this.mqttsPublish.getTopicId());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" + puback.getTopicId() + "\" to the client.");

+			break;

+

+			//if the TopicIdType is a shortTopicName 

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			puback.setShortTopicName(this.mqttsPublish.getShortTopicName());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" + puback.getShortTopicName() + "\" (short topic name) to the client.");

+

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			puback.setTopicId(this.mqttsPublish.getTopicId());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBACK message with \"TopicId\" = \"" + puback.getTopicId() + "\" to the client.");

+

+			break;

+

+			//should never reach here because topicIdType was checked 

+			//already when we received the Mqtts PUBLISH message 

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Unknown topicIdType of the stored Mqtts PUBLISH message: " + this.mqttsPublish.getTopicIdType()+". The received Mqtt PUBACK message cannot be processed.");

+			return;				

+		}		

+

+		//send the Mqtts PUBACK message to the client

+		clientInterface.sendMsg(this.clientAddress, puback);

+

+		//"reset" the "waitingPuback" state of the gateway and delete Mqtts PUBLISH message

+		gateway.resetWaitingPuback();

+		this.mqttsPublish = null;

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PUBREC message.

+	 * 

+	 * @param receivedMsg The received MqttPubRec message.

+	 */

+	private void handleMqttPubRec(MqttPubRec receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PUBREC message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PUBREC message cannot be processed.");

+			return;

+		}

+

+		//construct a Mqtts PUBREC message

+		MqttsPubRec msg = new MqttsPubRec();

+		msg.setMsgId(receivedMsg.getMsgId());

+

+		//send the Mqtts PUBREC message to the client	

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBREC message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PUBREL message.

+	 * 

+	 * @param receivedMsg The received MqttPubRel message.

+	 */

+	private void handleMqttPubRel(MqttPubRel receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PUBREL message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PUBREL message cannot be processed.");

+			return;

+		}

+

+		//construct a Mqtts PUBREL message

+		MqttsPubRel msg = new MqttsPubRel();

+		msg.setMsgId(receivedMsg.getMsgId());

+

+		//send the Mqtts PUBREL message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBREL message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);

+

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PUBCOMP message.

+	 * 

+	 * @param receivedMsg The received MqttPubComp message.

+	 */

+	private void handleMqttPubComp(MqttPubComp receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PUBCOMP message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PUBCOMP message cannot be processed.");

+			return;

+		}

+

+		//construct a Mqtts PUBCOMP message

+		MqttsPubComp msg = new MqttsPubComp();

+		msg.setMsgId(receivedMsg.getMsgId());

+

+		//send the Mqtts PUBCOMP message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PUBCOMP message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);		

+	}

+

+

+	/**

+	 * The method that handles a Mqtt SUBACK message.

+	 * 

+	 * @param receivedMsg The received MqttSuback message.

+	 */

+	private void handleMqttSuback(MqttSuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt SUBACK message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt SUBACK message cannot be processed.");

+			return;

+		}

+

+		//if the gateway is not expecting a Mqtt SUBACK at this time, drop the received message and return

+		if(!gateway.isWaitingSuback()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtt SUBACK message from the broker. The received message cannot be processed.");

+			return;

+		}

+

+		//else, assure that the stored Mqtts SUBSCRIBE is not null (debugging checks)

+		if (this.mqttsSubscribe == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts SUBSCRIBE is null. The received Mqtt SUBACK message cannot be processed.");

+

+			//"reset" the "waitingSuback" state of the gateway

+			gateway.resetWaitingSuback();

+			return;

+		} 

+

+		//if the MsgId of the received Mqtt SUBACK is not the same with MsgId of the stored 

+		//Mqtts SUBSCRIBE message, drop the received message and return (don't delete any stored message)

+		if(receivedMsg.getMsgId() != this.mqttsSubscribe.getMsgId()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts SUBACK message does not match the MsgId (\""+this.mqttsSubscribe.getMsgId()+"\") of the stored Mqtts SUBSCRIBE message. The message cannot be processed.");

+			return;

+		}

+

+		//else construct a Mqtts SUBACK message

+		MqttsSuback suback = new MqttsSuback();

+

+		//populate the Mqtts SUBACK message with the information from the Mqtt SUBACK message

+		suback.setGrantedQoS(receivedMsg.getGrantedQoS());

+		suback.setMsgId(receivedMsg.getMsgId());

+		suback.setReturnCode(MqttsMessage.RETURN_CODE_ACCEPTED);

+

+

+		//check the TopicIdType in the stored Mqtts SUBSCRIBE message

+		switch(this.mqttsSubscribe.getTopicIdType()){

+

+		//if the TopicIdType is a TopicName

+		case MqttsMessage.TOPIC_NAME:

+			suback.setTopicIdType(MqttsMessage.NORMAL_TOPIC_ID);

+

+			//if contains wildcard characters

+			if(this.mqttsSubscribe.getTopicName().equals("#") 

+					|| this.mqttsSubscribe.getTopicName().equals("+")

+					|| this.mqttsSubscribe.getTopicName().indexOf("/#/") != -1 

+					|| this.mqttsSubscribe.getTopicName().indexOf("/+/") != -1

+					|| this.mqttsSubscribe.getTopicName().endsWith("/#")

+					|| this.mqttsSubscribe.getTopicName().endsWith("/+")

+					|| this.mqttsSubscribe.getTopicName().startsWith("#/")

+					|| this.mqttsSubscribe.getTopicName().startsWith("+/")){

+				//set the topicId of the Mqtts SUBACK message to 0x0000

+				suback.setTopicId(0);					

+			}else if(topicIdMappingTable.getTopicId(this.mqttsSubscribe.getTopicName()) != 0)

+				//if topic id already exists

+				suback.setTopicId(topicIdMappingTable.getTopicId(this.mqttsSubscribe.getTopicName()));

+			else{

+				//assign a new topicID to the topic name

+				int topicId = getNewTopicId();

+				topicIdMappingTable.assignTopicId(topicId, this.mqttsSubscribe.getTopicName());

+				suback.setTopicId(topicId);

+			}

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts SUBACK message with \"TopicId\" = \"" + suback.getTopicId() + "\" to the client.");

+

+			break;

+

+			//if the TopicIdType is a shortTopicName 

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			suback.setTopicIdType(MqttsMessage.SHORT_TOPIC_NAME);

+			suback.setShortTopicName(this.mqttsSubscribe.getShortTopicName());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts SUBACK message with \"TopicId\" = \"" + suback.getShortTopicName() + "\" (short topic name) to the client.");

+

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			suback.setTopicIdType(MqttsMessage.PREDIFINED_TOPIC_ID);

+			suback.setPredefinedTopicId(this.mqttsSubscribe.getPredefinedTopicId());

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts SUBACK message with \"TopicId\" = \"" + suback.getPredefinedTopicId() + "\" to the client.");

+

+			break;

+

+			//should never reach here because topicIdType was checked 

+			//already when we received the Mqtts SUBSCRIBE message 

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - UnknownTopicId type of the stored Mqtts SUBSCRIBE message: " + this.mqttsSubscribe.getTopicIdType()+". The received Mqtt SUBACK message cannot be processed.");

+			return;				

+		}

+

+		//send the Mqtts SUBACK message to the client

+		clientInterface.sendMsg(this.clientAddress, suback);

+

+		//"reset" the "waitingSuback" state of the gateway and delete Mqtts SUBSCRIBE message

+		gateway.resetWaitingSuback();

+		this.mqttsSubscribe = null;

+	}

+

+

+	/**

+	 * The method that handles a Mqtt UNSUBACK message.

+	 * 

+	 * @param receivedMsg The received MqttUnsuback message.

+	 */

+	private void handleMqttUnsuback(MqttUnsuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt UNSUBACK message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt UNSUBACK message cannot be processed.");

+			return;

+		}

+

+		//if the gateway is not expecting a Mqtt UNSUBACK at this time, drop the received message and return

+		if(!gateway.isWaitingUnsuback()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtt UNSUBACK message from the broker.The received message cannot be processed.");

+			return;

+		}

+

+		//else, assure that the stored Mqtts UNSUBSCRIBE is not null (debugging checks)

+		if (this.mqttsUnsubscribe == null){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - The stored Mqtts UNSUBSCRIBE is null.The received Mqtt UNSUBACK message cannot be processed.");

+

+			//"reset" the "waitingUnsuback" state of the gateway

+			gateway.resetWaitingUnsuback();

+			return;

+		} 

+

+		//if the MsgId of the received Mqtt UNSUBACK is not the same with MsgId of the stored 

+		//Mqtts UNSUBSCRIBE message, drop the received message and return (don't delete any stored message)

+		if(receivedMsg.getMsgId() != this.mqttsUnsubscribe.getMsgId()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - MsgId (\""+receivedMsg.getMsgId()+"\") of the received Mqtts UNSUBACK message does not match the MsgId (\""+this.mqttsUnsubscribe.getMsgId()+"\") of the stored Mqtts UNSUBSCRIBE message. The message cannot be processed.");

+			return;

+		}

+

+		//else remove the associated topicId from the mapping table

+		if(!(this.mqttsUnsubscribe.getTopicIdType() == MqttsMessage.SHORT_TOPIC_NAME || this.mqttsUnsubscribe.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID))

+			topicIdMappingTable.removeTopicId(this.mqttsUnsubscribe.getTopicName());

+

+		//construct a Mqtts UNSUBACK message

+		MqttsUnsuback unsuback = new MqttsUnsuback();

+

+		//set the msgId of Mqtts UNSUBACK message with the information from the Mqtt UNSUBACK message

+		unsuback.setMsgId(receivedMsg.getMsgId());

+

+		//send the Mqtts SUBACK message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts UNSUBACK message to the client.");

+		clientInterface.sendMsg(this.clientAddress, unsuback);

+

+		//"reset" the "waitingUnsuback" state of the gateway and delete Mqtts UNSUBSCRIBE message

+		gateway.resetWaitingUnsuback();

+		mqttsUnsubscribe = null;

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PINGREQ message.

+	 * 

+	 * @param receivedMsg The received MqttPingReq message.

+	 */

+	private void handleMqttPingReq(MqttPingReq receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PINGREQ message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PINGREQ message cannot be processed.");

+			return;

+		}

+

+		//construct a Mqtts PINGREQ message

+		MqttsPingReq msg = new MqttsPingReq();

+

+		//send the Mqtts PINGREQ message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PINGREQ message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);

+	}

+

+

+	/**

+	 * The method that handles a Mqtt PINGRESP message.

+	 * 

+	 * @param receivedMsg The received MqttPingResp message.

+	 */

+	private void handleMqttPingResp(MqttPingResp receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Mqtt PINGRESP message received.");

+

+		//if the client is not in state "Connected" drop the received message

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Mqtt PINGRESP message cannot be processed.");

+			return;

+		}

+

+		//construct a Mqtts PINGRESP message

+		MqttsPingResp msg = new MqttsPingResp();

+

+		//send the Mqtts PINGRESP message to the client

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts PINGRESP message to the client.");

+		clientInterface.sendMsg(this.clientAddress, msg);	

+	}

+

+

+

+	/******************************************************************************************/

+	/**                        HANDLING OF CONTROL MESSAGES AND TIMEOUTS	                **/

+	/****************************************************************************************/

+

+	/* (non-Javadoc)

+	 * @see org.eclipse.paho.mqttsn.gateway.core.MsgHandler#handleControlMessage(org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage)

+	 */

+	public void handleControlMessage(ControlMessage receivedMsg){

+		//get the type of the Control message and handle the message according to that type	

+		switch(receivedMsg.getMsgType()){

+		case ControlMessage.CONNECTION_LOST:

+			connectionLost();

+			break;

+

+		case ControlMessage.WAITING_WILLTOPIC_TIMEOUT:

+			handleWaitingWillTopicTimeout();

+			break;

+

+		case ControlMessage.WAITING_WILLMSG_TIMEOUT:

+			handleWaitingWillMsgTimeout();

+			break;

+

+		case ControlMessage.WAITING_REGACK_TIMEOUT:

+			handleWaitingRegackTimeout();

+			break;

+

+		case ControlMessage.CHECK_INACTIVITY:

+			handleCheckInactivity();

+			break;

+

+		case ControlMessage.SEND_KEEP_ALIVE_MSG:

+			//we will never receive such a message 

+			break;				

+

+		case ControlMessage.SHUT_DOWN:

+			shutDown();

+			break;			

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}

+

+

+	/**

+	 * The method that is invoked when the TCP/IP connection with the broker was lost.

+	 */

+	private void connectionLost() {

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control CONNECTION_LOST message received.");

+

+		//if the client is not in state "Connected" return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The call on connectionLost() method has no effect.");

+			return;

+		}

+

+		GatewayLogger.log(GatewayLogger.ERROR, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - TCP/IP connection with the broker was lost.");

+

+		//call the sendClientDisconnect method of this handler

+		sendClientDisconnect();

+	}

+

+

+	/**

+	 * The method that is invoked when waiting for a Mqtts WILLTOPIC message from

+	 * the client has timeout.

+	 */

+	private void handleWaitingWillTopicTimeout(){

+		GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control WAITING_WILLTOPIC_TIMEOUT message received.");

+

+		//check if the gateway is still in state of waiting for a WILLTOPIC message from the client

+		if(!gateway.isWaitingWillTopic()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtts WILLTOPIC message from the client. The received control WAITING_WILLTOPIC_TIMEOUT message cannot be processed.");

+			return;

+		}

+

+		//if we have reached the maximum tries of sending Mqtts WILLTOPICREQ message

+		if(gateway.getTriesSendingWillTopicReq() > GWParameters.getMaxRetries()){

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Maximum retries of sending Mqtts WILLTOPICREQ message to the client were reached. The message will not be sent again.");		

+

+			//"reset" the "waitingWillTopic" state of the gateway, "reset" the tries of sending 

+			//Mqtts WILLTOPICREQ message to the client, unregister from the timer and and delete 

+			//the stored Mqtts CONNECT message

+			gateway.resetWaitingWillTopic();

+			gateway.resetTriesSendingWillTopicReq();

+			timer.unregister(this.clientAddress, ControlMessage.WAITING_WILLTOPIC_TIMEOUT);

+			this.mqttsConnect = null;

+

+			//else construct a Mqtts WILTOPICREQ, and send it to the client

+		}else{			

+			MqttsWillTopicReq willTopicReq = new MqttsWillTopicReq();

+

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Re-sending Mqtts WILLTOPICREQ message to the client. Retry: "+gateway.getTriesSendingWillTopicReq()+".");		

+			clientInterface.sendMsg(this.clientAddress, willTopicReq);	

+

+			//increase the tries of sending Mqtts WILLTOPICREQ message to the client

+			gateway.increaseTriesSendingWillTopicReq();

+		}

+	}

+

+

+	/**

+	 * The method that is invoked when waiting for a Mqtts WILLMSG message from

+	 * the client has timeout.

+	 */

+	private void handleWaitingWillMsgTimeout(){

+		GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control WAITING_WILLMSG_TIMEOUT message received.");

+

+		//check if the gateway is still in state of waiting for a WILLMSG message from the client

+		if(!gateway.isWaitingWillMsg()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not waiting a Mqtts WILLMSG message from the client. The received control WAITING_WILLMSG_TIMEOUT message cannot be processed.");

+			return;

+		}

+

+		//if we have reached the maximum tries of sending Mqtts WILLMSGREQ message

+		if(gateway.getTriesSendingWillMsgReq() > GWParameters.getMaxRetries()){

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Maximum retries of sending Mqtts WILLMSGREQ message to the client were reached. The message will not be sent again.");

+			//"reset" the "waitingWillMsg" state of the gateway, "reset" the tries of sending

+			//Mqtts WILLMSGREQ message to the client, unregister from the timer and delete 

+			//the stored Mqtts CONNECT and Mqtts WILLTOPIC messages

+			gateway.resetWaitingWillMsg();

+			gateway.resetTriesSendingWillMsgReq();

+			timer.unregister(this.clientAddress, ControlMessage.WAITING_WILLMSG_TIMEOUT);

+			this.mqttsConnect = null;

+			this.mqttsWillTopic = null;

+

+			//else construct a Mqtts WILMSGREQ and send it to the client

+		}else{			

+			MqttsWillMsgReq willMsgReq = new MqttsWillMsgReq();

+

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Re-sending Mqtts WILLMSGREQ message to the client. Retry: "+gateway.getTriesSendingWillMsgReq()+".");

+			clientInterface.sendMsg(this.clientAddress, willMsgReq);

+

+			//increase the tries of sending Mqtts WILLMSGREQ message to the client

+			gateway.increaseTriesSendingWillMsgReq();

+		}

+	}

+

+

+	/**

+	 * The method that is invoked when waiting for a Mqtts REGACK message from

+	 * the client has timeout.

+	 */

+	private void handleWaitingRegackTimeout(){

+		GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control WAITING_REGACK_TIMEOUT message received.");

+

+		//check if the gateway is still in state of waiting for a REGACK message from the client

+		if(!gateway.isWaitingRegack()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Gateway is not in state of waiting a Mqtts REGACK message from the client. The received control REGACK_TIMEOUT message cannot be processed.");

+			return;

+		}

+

+		//if we have reached the maximum tries of sending the Mqtts REGISTER message

+		if(gateway.getTriesSendingRegister() > GWParameters.getMaxRetries()){

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Maximum retries of sending Mqtts REGISTER message to the client were reached. The message will not be sent again.");

+			//"reset" the 'waitingRegack" state of the gateway, "reset" the tries of sending

+			//Mqtts REGISTER message to the client, unregister from the timer and delete

+			//the stored Mqtt PUBLISH and Mqtts REGISTER messages

+			gateway.resetWaitingRegack();

+			gateway.resetTriesSendingRegister();

+			timer.unregister(this.clientAddress, ControlMessage.WAITING_REGACK_TIMEOUT);

+			this.mqttPublish = null;

+			this.mqttsRegister = null;

+		}	

+

+		//else modify the MsgId (get a new one) of the stored Mqtts 

+		//REGISTER message, and send it to the client

+		else{			

+			this.mqttsRegister.setMsgId(getNewMsgId());

+

+			GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Re-sending Mqtts REGISTER message to the client. Retry: "+gateway.getTriesSendingRegister()+".");

+			clientInterface.sendMsg(this.clientAddress, this.mqttsRegister);

+			gateway.increaseTriesSendingRegister();

+		}

+	}

+

+

+	/**

+	 * This method is invoked in regular intervals to check the inactivity of this handler

+	 * in order to remove it from Dispatcher's mapping table.

+	 */

+	private void handleCheckInactivity() {

+		GatewayLogger.log(GatewayLogger.INFO, 

+				"ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+

+				"]/["+clientId+"] - Control CHECK_INACTIVITY message received.");

+

+		if(System.currentTimeMillis() > this.timeout){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is inactive for more than "+ GWParameters.getHandlerTimeout()/60+ " minutes. The associated ClientMsgHandler will be removed from Dispatcher's mapping table.");

+

+			//close broker connection (if any)

+			brokerInterface.disconnect();

+

+			dispatcher.removeHandler(this.clientAddress);

+		}

+	}

+

+	/**

+	 * This method is invoked when the gateway is shutting down.

+	 */

+	private void shutDown(){

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Control SHUT_DOWN message received.");

+

+		//if the client is not in state "Connected" return

+		if(!client.isConnected()){

+			GatewayLogger.log(GatewayLogger.WARN, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Client is not connected. The received Control SHUT_DOWN message cannot be processed.");

+			return;

+		}

+

+		//stop the reading thread of the BrokerInterface

+		//(this does not have any effect to the input and output streams which remain active)

+		brokerInterface.setRunning(false);

+

+		//construct a Mqtt DISCONNECT message

+		MqttDisconnect mqttDisconnect = new MqttDisconnect();

+

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt DISCONNECT message to the broker.");

+		//send the Mqtt DISCONNECT message to the broker

+		//(don't bother if the sending of Mqtt DISCONNECT message to the broker was successful or not)

+		try {

+			brokerInterface.sendMsg(mqttDisconnect);

+		} catch (MqttsException e) {

+			// do nothing

+		}		

+	}

+

+

+	/******************************************************************************************/

+	/**                                   OTHER METHODS AND CLASSES       	                **/

+	/****************************************************************************************/

+

+

+	/**

+	 * The method that sets the Client interface in which this handler should respond in case 

+	 * of sending a Mqtts message to the client.

+	 * 

+	 * @param clientInterface

+	 */

+	public void setClientInterface(ClientInterface clientInterface) {

+		this.clientInterface = clientInterface;

+	}

+

+

+	/**

+	 * This method sends a Mqtts DISCONNECT message to the client.

+	 */

+	private void sendClientDisconnect() {

+		//construct a Mqtts DISCONNECT message

+		MqttsDisconnect mqttsDisconnect = new MqttsDisconnect();

+

+		//send the Mqtts DISCONNECT message to the client	

+		GatewayLogger.log(GatewayLogger.INFO, "ClientMsgHandler ["+Utils.hexString(this.clientAddress.getAddress())+"]/["+clientId+"] - Sending Mqtts DISCONNECT message to the client.");

+		clientInterface.sendMsg(this.clientAddress, mqttsDisconnect);

+

+		//set the state of the client to "Disconnected"

+		client.setDisconnected();

+

+		//remove timer registrations (if any)

+		timer.unregister(this.clientAddress);

+

+		//"reset" all the states and the retry counters of the gateway

+		gateway.reset();

+

+		//close the connection with the broker (if any)

+		brokerInterface.disconnect();

+		//topicIdMappingTable.printContent();

+	}

+

+

+	/**

+	 * This method generates and return a unique message ID.

+	 * 

+	 * @return The message ID

+	 */

+	private int getNewMsgId(){

+		return msgId ++;

+	}

+

+	/**

+	 *This method generates and return a unique topic ID.

+	 * 

+	 * @return A unique topic ID

+	 */

+	private int getNewTopicId(){

+		return topicId ++;

+	}

+

+

+	/**

+	 * The class that represents the state of the client at any given time.

+	 *

+	 */

+	private class ClientState {

+

+		private final int NOT_CONNECTED = 1;

+		private final int CONNECTED 	= 2;

+		private final int DISCONNECTED 	= 3;

+

+		private int state;

+

+		public ClientState(){

+			state = NOT_CONNECTED;

+		}

+

+//		public boolean isNotConnected() {

+//			return (state == NOT_CONNECTED);

+//		}

+

+//		public void setNotConnected() {

+//			state = NOT_CONNECTED;

+//		}

+

+		public boolean isConnected() {

+			return (state == CONNECTED);

+		}

+

+		public void setConnected() {

+			state = CONNECTED;

+		}

+

+//		public boolean isDisconnected() {

+//			return (state == DISCONNECTED);

+//		}

+

+		public void setDisconnected() {

+			state = DISCONNECTED;

+		}

+	}

+

+

+	/**

+	 * The class that represents the state of the gateway at any given time.

+	 *

+	 */

+	private class GatewayState {

+

+		//waiting message from the client

+		private boolean waitingWillTopic;

+		private boolean waitingWillMsg;

+		private boolean waitingRegack;

+

+		//waiting message from the broker

+		private boolean waitingSuback;

+		private boolean waitingUnsuback;

+		private boolean waitingPuback;

+

+		//counters

+		private int triesSendingWillTopicReq;

+		private int triesSendingWillMsgReq;

+		private int triesSendingRegister;

+

+		public GatewayState(){

+			this.waitingWillTopic = false;

+			this.waitingWillMsg = false;		

+			this.waitingRegack = false;

+

+			this.waitingSuback = false;

+			this.waitingUnsuback = false;

+			this.waitingPuback = false;

+

+			this.triesSendingWillTopicReq = 0;

+			this.triesSendingWillMsgReq = 0;

+			this.triesSendingRegister = 0;

+		}

+

+

+		public void reset(){

+			this.waitingWillTopic = false;

+			this.waitingWillMsg = false;		

+			this.waitingRegack = false;

+

+			this.waitingSuback = false;

+			this.waitingUnsuback = false;

+			this.waitingPuback = false;

+

+

+			this.triesSendingWillTopicReq = 0;

+			this.triesSendingWillMsgReq = 0;

+			this.triesSendingRegister = 0;

+

+			//delete also all stored messages (if any)  

+			mqttsConnect = null;

+			mqttsWillTopic = null;	

+			mqttsSubscribe = null;

+			mqttsUnsubscribe = null;

+			mqttsRegister = null;

+			mqttsPublish = null;

+			mqttPublish = null;

+		}

+

+

+		public boolean isEstablishingConnection() {

+			return (isWaitingWillTopic() || isWaitingWillMsg());

+		}

+

+

+		public boolean isWaitingWillTopic() {

+			return this.waitingWillTopic;

+		}

+

+		public void setWaitingWillTopic() {

+			this.waitingWillTopic = true;

+		}

+

+		public void resetWaitingWillTopic() {

+			this.waitingWillTopic = false;

+		}

+

+

+		public boolean isWaitingWillMsg() {

+			return this.waitingWillMsg;

+		}

+

+		public void setWaitingWillMsg() {

+			this.waitingWillMsg = true;

+		}

+

+		public void resetWaitingWillMsg() {

+			this.waitingWillMsg = false;

+		}

+

+

+		public boolean isWaitingRegack() {

+			return this.waitingRegack;

+		}

+

+		public void setWaitingRegack() {

+			this.waitingRegack = true;

+		}

+

+		public void resetWaitingRegack() {

+			this.waitingRegack = false;

+		}

+

+

+		public boolean isWaitingSuback() {

+			return this.waitingSuback;

+		}

+

+		public void setWaitingSuback() {

+			this.waitingSuback = true;

+		}

+

+		public void resetWaitingSuback() {

+			this.waitingSuback = false;

+		}

+

+

+		public boolean isWaitingUnsuback() {

+			return this.waitingUnsuback;

+		}

+

+		public void setWaitingUnsuback() {

+			this.waitingUnsuback = true;

+		}

+

+		public void resetWaitingUnsuback() {

+			this.waitingUnsuback = false;

+		}

+

+

+		public boolean isWaitingPuback() {

+			return this.waitingPuback;

+		}

+

+		public void setWaitingPuback() {

+			this.waitingPuback = true;

+		}

+

+		public void resetWaitingPuback() {

+			this.waitingPuback = false;

+		}

+

+

+

+		public int getTriesSendingWillTopicReq() {

+			return this.triesSendingWillTopicReq;

+		}

+

+		public void increaseTriesSendingWillTopicReq() {

+			this.triesSendingWillTopicReq ++;

+		}

+

+		public void resetTriesSendingWillTopicReq() {

+			this.triesSendingWillTopicReq = 0;

+		}

+

+

+

+		public int getTriesSendingWillMsgReq() {

+			return this.triesSendingWillMsgReq;

+		}

+

+		public void increaseTriesSendingWillMsgReq() {

+			this.triesSendingWillMsgReq ++;

+		}

+

+		public void resetTriesSendingWillMsgReq() {

+			this.triesSendingWillMsgReq = 0;

+		}

+

+

+

+		public int getTriesSendingRegister() {

+			return this.triesSendingRegister;

+		}

+

+		public void increaseTriesSendingRegister() {

+			this.triesSendingRegister ++;

+		}	

+

+		public void resetTriesSendingRegister() {

+			this.triesSendingRegister = 0;

+		}

+	}

+

+	/*	private void printState(String string) {

+		System.out.println(string);

+		System.out.println("client.isNotDisconnected = "+client.isNotConnected());

+		System.out.println("client.isConnected = "+client.isConnected());

+		System.out.println("client.isDisconnected = "+client.isDisconnected());	

+

+		System.out.println("gateway.waitingWillTopic = "+gateway.isWaitingWillTopic());

+		System.out.println("gateway.waitingWillMsg = "+gateway.isWaitingWillMsg());

+		System.out.println("gateway.triesSendingWillTopicReq = "+gateway.getTriesSendingWillTopicReq());

+		System.out.println("gateway.triesSendingWillMsgReq = "+gateway.getTriesSendingWillMsgReq());

+		System.out.println("gateway.waitingRegack = "+gateway.isWaitingRegack());

+		System.out.println("gateway.triesSendingRegister = "+gateway.getTriesSendingRegister());

+		System.out.println("gateway.waitingSuback = "+gateway.isWaitingSuback());

+		System.out.println("gateway.waitingUnsuback = "+gateway.isWaitingUnsuback());

+

+		System.out.println("handler.mqttsConnect = "+mqttsConnect);

+		System.out.println("handler.mqttsWillTopic = "+mqttsWillTopic);

+		System.out.println("handler.mqttsRegister = "+mqttsRegister);

+		System.out.println("handler.mqttPublish = "+mqttPublish);

+		System.out.println("handler.mqttsSubscribe = "+mqttsSubscribe);

+		System.out.println("handler.mqttsUnsubscribe  = "+mqttsUnsubscribe );

+	}*/

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/Dispatcher.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/Dispatcher.java
new file mode 100644
index 0000000..50ffd00
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/Dispatcher.java
@@ -0,0 +1,337 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.core;

+

+import java.util.Enumeration;

+import java.util.Hashtable;

+import java.util.Iterator;

+

+//import org.eclipse.paho.mqttsn.gateway.Gateway;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+import org.eclipse.paho.mqttsn.gateway.utils.Address;

+import org.eclipse.paho.mqttsn.gateway.utils.ClientAddress;

+//import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+import org.eclipse.paho.mqttsn.gateway.utils.MsgQueue;

+

+/**

+ * This object dispatches messages to the appropriate MsgHandler according to the

+ * client address they carry.

+ * 

+ *

+ */

+public class Dispatcher implements Runnable{

+

+	private static Dispatcher instance = null;

+

+	private MsgQueue dataQueue; 

+	private Hashtable<Address, MsgHandler> handlerTable;

+	private volatile boolean running;

+	private Thread readingThread;

+

+

+	/**

+	 * Initialization method.

+	 */

+	public void initialize(){

+		dataQueue = new MsgQueue();

+		handlerTable = new Hashtable<Address, MsgHandler>();				

+		this.running = true;

+		this.readingThread = new Thread(this,"Dispatcher");

+		this.readingThread.start();

+	}

+

+

+	/**

+	 * This method returns the instance of this object.If there no such an instance

+	 * a new object is created.

+	 * 

+	 * @return The instance of this object.

+	 */

+	public static synchronized Dispatcher getInstance() {

+		if (instance == null) {

+			instance = new Dispatcher();

+		}

+		return instance;

+	}

+

+

+	/**

+	 * The method that reads a message {@link org.eclipse.paho.mqttsn.gateway.messages.Message} from 

+	 * the queue and dispatches it according to its type (Mqtts, Mqtt or Control message).

+	 */

+	private void dispatch() {

+		//read the next available Message from queue

+

+		Message msg = null;

+		try {

+			msg = (Message)dataQueue.get();

+		} catch (InterruptedException e) {

+			e.printStackTrace();

+		}

+

+		//get the type of the message that "internal" message carries

+		int type = msg.getType();

+		switch(type){		

+		case Message.MQTTS_MSG:

+			dispatchMqtts(msg);

+			break;

+

+		case Message.MQTT_MSG:

+			dispatchMqtt(msg);

+			break;

+

+		case Message.CONTROL_MSG:

+			dispatchControl(msg);

+			break;

+

+		default:

+			GatewayLogger.warn("Dispatcher - Message of unknown type \"" + msg.getType()+"\" received.");

+			break;

+		}

+	}

+

+

+	/**

+	 * The method that handles a Mqtts message.According to its address is dispatched

+	 * to the appropriate MsgHandler.

+	 * 

+	 * @param msg

+	 */

+	private void dispatchMqtts(Message msg) {

+		//		GatewayLogger.log(GatewayLogger.INFO, "Dispatcher - New Mqtts message arrived at queue.");

+

+		//get the address of the client from this message

+		Address address = msg.getAddress(); 

+

+		//get the Mqtts message itself

+		MqttsMessage mqttsMsg = msg.getMqttsMessage();

+

+		if(mqttsMsg == null){

+			GatewayLogger.log(GatewayLogger.WARN, 

+					"Dispatcher - The received Mqtts message is null. The message cannot be processed.");

+			return;

+		}

+

+		//get the appropriate handler (GatewayMsgHandler or ClientMsgHandler)for this message 

+		//according to the unique address of the client (or the gateway)

+		MsgHandler handler = getHandler(address);

+

+		if (handler == null){

+			//there is no such a handler, create a new one (applies only for the case of ClientMsgHandler

+			//because GatewayMsgHandler was inserted in the hashtable at the startup of the gateway)

+			ClientAddress clientAddress = (ClientAddress) address;	

+			handler = new ClientMsgHandler(clientAddress);

+			putHandler(clientAddress,handler);

+			handler.initialize();

+		}

+

+		//update the client interface of the MsgHandler (if the handler is a ClientMsgHandler)

+		if(handler instanceof ClientMsgHandler && msg.getClientInterface() != null){

+			ClientMsgHandler clientHandler = (ClientMsgHandler) handler;

+			clientHandler.setClientInterface(msg.getClientInterface());

+		}

+

+		//pass the message to the handler

+		handler.handleMqttsMessage(mqttsMsg);		

+	}

+

+

+	/**

+	 * The method that handles a Mqtt message.According to its address is dispatched

+	 * to the appropriate MsgHandler.

+	 * 

+	 * @param msg

+	 */

+	private void dispatchMqtt(Message msg) {

+		//		GatewayLogger.log(GatewayLogger.INFO, "Dispatcher - New Mqtt message arrived at queue.");

+

+		//get the address of the client from this message

+		Address address = msg.getAddress(); 

+

+		//get the Mqtt message itself

+		MqttMessage mqttMsg = msg.getMqttMessage();

+

+		if(mqttMsg == null){

+			GatewayLogger.log(GatewayLogger.WARN, 

+					"Dispatcher - The received Mqtt message is null. The message cannot be processed.");

+			return;

+		}

+

+		//get the appropriate handler (GatewayMsgHandler or ClientMsgHandler)for this message 

+		//according to the unique address of the client (or the gateway)

+		MsgHandler handler = getHandler(address);

+

+		if (handler == null){

+			//there is no such a handler, create a new one (applies only for the case of ClientMsgHandler

+			//because GatewayMsgHandler was inserted in the hashtable when Dispatcher was created)

+			ClientAddress clientAddress = (ClientAddress) address;	

+			handler = new ClientMsgHandler(clientAddress);

+			putHandler(clientAddress,handler);

+			handler.initialize();

+		}	

+

+		//pass the message to the handler

+		handler.handleMqttMessage(mqttMsg);		

+	}

+

+

+	/**

+	 * The method that handles a Control message.According to its address is dispatched

+	 * to the appropriate MsgHandler.

+	 * 

+	 * @param msg

+	 */

+	private void dispatchControl(Message msg) {

+		//		GatewayLogger.log(GatewayLogger.INFO, "Dispatcher - New Control message arrived at queue.");

+

+		//get the address of the client from this message

+		Address address = msg.getAddress(); 

+

+

+		//get the Control message itself

+		ControlMessage controlMsg = msg.getControlMessage();

+

+		if(controlMsg == null){

+			GatewayLogger.log(GatewayLogger.WARN, 

+					"Dispatcher - The received Control message is null. The message cannot be processed.");

+			return;

+		}

+

+		if(address == null){

+			//this message applies to all message handlers

+			//			GatewayLogger.log(GatewayLogger.INFO, "Dispatcher - The received Control message is addressed to all handlers.");

+			deliverMessageToAll(controlMsg);

+			return;

+		}

+

+		//get the appropriate handler (GatewayMsgHandler or ClientMsgHandler)for this message 

+		//according to the unique address of the client (or the gateway)

+		MsgHandler handler = getHandler(address);

+

+		if (handler == null){

+			//there is no such a handler, create a new one (applies only for the case of ClientMsgHandler

+			//because GatewayMsgHandler was inserted in the hashtable when Dispatcher was created)

+			ClientAddress clientAddress = (ClientAddress) address;	

+			handler = new ClientMsgHandler(clientAddress);

+			putHandler(clientAddress,handler);

+			handler.initialize();

+		}

+

+		//pass the message to the handler

+		handler.handleControlMessage(controlMsg);			

+	}

+

+

+	/**

+	 * This method delivers a message to all MsgHandlers.

+	 */

+	private void deliverMessageToAll(ControlMessage msg) {

+		Enumeration<MsgHandler> values;

+		MsgHandler handler;

+

+		if(msg.getMsgType() == ControlMessage.SHUT_DOWN){			

+			GatewayLogger.info("-------- Mqtts Gateway shutting down --------");

+		}

+		for(values = handlerTable.elements(); values.hasMoreElements();){

+			handler = (MsgHandler)values.nextElement();

+			handler.handleControlMessage(msg);

+		}

+

+		if(msg.getMsgType() == ControlMessage.SHUT_DOWN){

+			GatewayLogger.info("-------- Mqtts Gateway stopped --------");

+			System.exit(0);

+		}

+	}

+

+

+	/**

+	 * The method that puts a new created MsgHandler to the mapping table.

+	 * 

+	 * @param addr The address of the handler

+	 * @param handler The new created handler object

+	 */

+	public void putHandler(Address addr, MsgHandler handler) {

+		this.handlerTable.put(addr, handler);		

+	}

+

+

+	/**

+	 * 

+	 * The method that gets a MsgHandler from the mapping table according to its address.

+	 * 

+	 * @param addr The address of the handler

+	 * @return The handler object

+	 */

+	private MsgHandler getHandler(Address addr) {

+		MsgHandler ret = null;

+		Iterator<Address> iter = handlerTable.keySet().iterator();

+		while (iter.hasNext()) {

+			Address currentAddress = (Address)(iter.next());

+			if(currentAddress.equal(addr) && addr.equal(currentAddress)) {

+				currentAddress.setIPaddress(addr);

+				ret = (MsgHandler)handlerTable.get(currentAddress);

+				break;

+			}

+		}

+		return ret;

+	}	

+

+

+	/**

+	 * The method that removes an MsgHandler from the mapping table.

+	 * 

+	 * @param addr The address of the handler

+	 */

+	public void removeHandler(Address address) {

+		Iterator<Address> iter  =  handlerTable.keySet().iterator();

+		while (iter.hasNext()) {	

+			Address currentAddress = (Address)(iter.next());

+			if(currentAddress.equal(address)){

+				iter.remove();

+				break;

+			}

+		}		

+	}	

+

+

+	/**

+	 * The method that puts a message {@link org.eclipse.paho.mqttsn.gateway.messages.Message}

+	 * to the queue.

+	 * 

+	 * @param msg

+	 */

+	public void putMessage(Message msg) {

+		if(msg.getType() == Message.CONTROL_MSG)

+			dataQueue.addFirst(msg);

+		else

+			dataQueue.addLast(msg);

+	}

+

+

+	/* (non-Javadoc)

+	 * @see java.lang.Runnable#run()

+	 */

+	public void run() {

+		while(running){

+			dispatch();

+		}		

+	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/GatewayMsgHandler.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/GatewayMsgHandler.java
new file mode 100644
index 0000000..83b1703
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/GatewayMsgHandler.java
@@ -0,0 +1,828 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.core;

+

+import java.util.StringTokenizer;

+import java.util.Vector;

+

+import org.eclipse.paho.mqttsn.gateway.broker.tcp.TCPBrokerInterface;

+import org.eclipse.paho.mqttsn.gateway.client.ClientInterface;

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttConnack;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttConnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttDisconnect;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingReq;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPingResp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubComp;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRec;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPubRel;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttPublish;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttSuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttUnsuback;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsAdvertise;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsGWInfo;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsPublish;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsSearchGW;

+import org.eclipse.paho.mqttsn.gateway.timer.TimerService;

+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayAddress;

+import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+public class GatewayMsgHandler extends MsgHandler{

+

+	private GatewayAddress gatewayAddress = null;

+	private TCPBrokerInterface brokerInterface = null;

+	private TimerService timer = null;

+	private Dispatcher dispatcher;

+	private long advPeriodCounter = 0;

+	private long checkingCounter = 0;

+	private TopicMappingTable topicIdMappingTable;

+	private String clientId;

+

+	private boolean connected;

+	private Vector<ClientInterface> clientInterfacesVector;

+

+

+	/**

+	 * 

+	 */

+	public GatewayMsgHandler(GatewayAddress addr) {

+		this.gatewayAddress = addr;

+	}

+

+	public void initialize(){			

+		brokerInterface = new TCPBrokerInterface(this.gatewayAddress);

+		timer = TimerService.getInstance();

+		dispatcher = Dispatcher.getInstance();

+		topicIdMappingTable = new TopicMappingTable();

+		topicIdMappingTable.initialize();		

+		clientId = "Gateway_" + GWParameters.getGwId();

+

+		GatewayLogger.info("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Establishing TCP/IP connection with "+

+				GWParameters.getBrokerURL());

+

+		//open a new TCP/IP connection with the broker 

+		try {

+			brokerInterface.initialize();

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.error("GatewayMsgHandler ["+

+					Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+					"]/["+clientId+"] - Failed to establish TCP/IP connection with " +

+					GWParameters.getBrokerURL()+ ". Gateway cannot start.");

+			System.exit(1);

+

+		}		

+		GatewayLogger.info("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - TCP/IP connection established.");

+	}

+

+

+	/******************************************************************************************/

+	/**                             HANDLING OF MQTTS MESSAGES 		                        **/

+	/****************************************************************************************/

+

+	public void handleMqttsMessage(MqttsMessage receivedMsg){

+		//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 

+			break;

+

+		case MqttsMessage.CONNACK:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.WILLTOPICREQ:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.WILLTOPIC:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.WILLMSGREQ:

+			//we will never receive such a message

+			break;

+

+		case MqttsMessage.WILLMSG:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.REGISTER:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.REGACK:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.PUBLISH:

+			handleMqttsPublish((MqttsPublish) receivedMsg);

+			break;

+

+		case MqttsMessage.PUBACK:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.PUBCOMP:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.PUBREC:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.PUBREL:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.SUBSCRIBE:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.SUBACK:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.UNSUBSCRIBE:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.UNSUBACK:

+			//we will never receive such a message

+			break;

+

+		case MqttsMessage.PINGREQ:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.PINGRESP:

+			//we will never receive such a message 

+			break;			

+

+		case MqttsMessage.DISCONNECT:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.WILLTOPICUPD:

+			//we will never receive such a message 

+			break;

+

+		case MqttsMessage.WILLTOPICRESP:

+			//we will never receive such a message

+			break;

+

+		case MqttsMessage.WILLMSGUPD: 

+			//we will never receive such a message

+			break;

+

+		case MqttsMessage.WILLMSGRESP:

+			//we will never receive such a message

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtts message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}

+

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttsAdvertise(MqttsAdvertise receivedMsg) {

+		// TODO implement this method for load balancing issues

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtts ADVERTISE message received.");

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttsSearchGW(MqttsSearchGW receivedMsg) {		

+		//		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtts SEARCHGW message with \"Radius\" = \""+receivedMsg.getRadius()+"\" received.");

+

+		//construct a Mqtts GWINFO message for the reply to the received Mqtts SEARCHGW message

+		MqttsGWInfo msg = new MqttsGWInfo();

+		msg.setGwId(GWParameters.getGwId());

+

+		//get the broadcast radius 

+		byte radius = (byte)receivedMsg.getRadius();

+

+		//broadcast the Mqtts GWINFO message to the network

+		//		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Broadcasting Mqtts GWINFO message to the network with broadcast radius \""+radius+"\".");

+

+		Vector<?> interfaces = GWParameters.getClientInterfaces();

+		for(int i = 0; i < interfaces.size(); i++){

+			ClientInterface inter = (ClientInterface) interfaces.get(i);

+			inter.broadcastMsg(radius, msg);

+		}		

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttsGWInfo(MqttsGWInfo receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtts GWINFO message received.");

+

+		// TODO implement this method for load balancing issues

+

+	}

+

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttsPublish(MqttsPublish receivedMsg) {

+		if(receivedMsg.getTopicIdType() == MqttsMessage.NORMAL_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getTopicId()+"\" received.");

+		else if (receivedMsg.getTopicIdType() == MqttsMessage.PREDIFINED_TOPIC_ID)

+			GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getTopicId()+"\" (predefined topic Id) received.");

+		else

+			GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Mqtts PUBLISH message with \"QoS\" = \""+receivedMsg.getQos()+"\" and \"TopicId\" = \""+receivedMsg.getShortTopicName()+"\" (short topic name) received.");

+

+		//construct a Mqtt PUBLISH message

+		MqttPublish publish = new MqttPublish();

+

+		//check the TopicIdType in the received Mqtts PUBLISH message

+		switch(receivedMsg.getTopicIdType()){

+

+		//if the TopicIdType is a normal TopicId

+		case MqttsMessage.NORMAL_TOPIC_ID:

+			GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Topic Id type "+ receivedMsg.getTopicIdType()+" is invalid. Publish with \"QoS\" = \"-1\" supports only predefined topis Ids (topic Id type = \"1\") or short topic names (topic Id type = \"2\").");

+			return;

+

+			//if the TopicIdType is a shortTopicName then simply copy it to the topicName field of the Mqtt PUBLISH message

+		case MqttsMessage.SHORT_TOPIC_NAME:

+			publish.setTopicName(receivedMsg.getShortTopicName());	

+			break;

+

+			//if the TopicIdType is a predifinedTopiId

+		case MqttsMessage.PREDIFINED_TOPIC_ID:

+			if(receivedMsg.getTopicId() > GWParameters.getPredfTopicIdSize()){

+				GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message is out of the range of predefined topic Ids [1,"+GWParameters.getPredfTopicIdSize()+"]. The message cannot be processed.");

+				return;

+			}				

+

+			//get the predefined topic name that corresponds to the received predefined topicId

+			String topicName = topicIdMappingTable.getTopicName(receivedMsg.getTopicId());

+

+			//this should not happen as predefined topic ids are already stored

+			if(topicName == null){

+				GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Predefined topicId (\"" + receivedMsg.getTopicId() + "\") of the received Mqtts PUBLISH message does not exist. The message cannot be processed.");

+				return;

+			}

+			publish.setTopicName(topicName);

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Unknown topicIdType (\"" + receivedMsg.getTopicIdType()+"\"). The received Mqtts PUBLISH message cannot be processed.");

+			return;	

+		}

+

+		//populate the Mqtt PUBLISH message 

+		publish.setDup(false);

+

+		//set QoS = 0

+		publish.setQos(0);

+		publish.setRetain(false);

+

+		//there is no msg id in QoS = 0 publish messages

+

+		publish.setPayload(receivedMsg.getData());

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt PUBLISH message with \"QoS\" = \""+publish.getQos()+"\" and \"TopicName\" = \""+publish.getTopicName()+ "\" to the broker.");

+

+		//send the Mqtt PUBLISH message to the broker

+		try {

+			brokerInterface.sendMsg(publish);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.log(GatewayLogger.ERROR, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed sending Mqtt PUBLISH message to the broker.");

+			connectionLost();

+		}

+	}

+

+

+	/******************************************************************************************/

+	/**                      HANDLING OF MQTT MESSAGES FROM THE BROKER                      **/

+	/****************************************************************************************/

+

+	/**

+	 * @param receivedMsg

+	 */

+	public void handleMqttMessage(MqttMessage receivedMsg){

+		//get the type of the Mqtt message and handle the message according to that type	

+		switch(receivedMsg.getMsgType()){

+		case MqttMessage.CONNECT:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.CONNACK:

+			handleMqttConnack((MqttConnack) receivedMsg);

+			break;

+

+		case MqttMessage.PUBLISH:

+			handleMqttPublish((MqttPublish) receivedMsg);

+			break;

+

+		case MqttMessage.PUBACK:

+			handleMqttPuback((MqttPuback)receivedMsg);

+			break;

+

+		case MqttMessage.PUBREC:

+			handleMqttPubRec((MqttPubRec) receivedMsg);

+			break;

+

+		case MqttMessage.PUBREL:

+			handleMqttPubRel((MqttPubRel)receivedMsg);

+			break;

+

+		case MqttMessage.PUBCOMP:

+			handleMqttPubComp((MqttPubComp) receivedMsg);

+			break;

+

+		case MqttMessage.SUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;				

+

+		case MqttMessage.SUBACK:

+			handleMqttSuback((MqttSuback) receivedMsg);

+			break;

+

+		case MqttMessage.UNSUBSCRIBE:

+			//we will never receive such a message from the broker

+			break;

+

+		case MqttMessage.UNSUBACK:

+			handleMqttUnsuback((MqttUnsuback) receivedMsg);

+			break;

+

+		case MqttMessage.PINGREQ:

+			handleMqttPingReq((MqttPingReq) receivedMsg);

+			break;

+

+		case MqttMessage.PINGRESP:

+			handleMqttPingResp((MqttPingResp) receivedMsg);

+			break;

+

+		case MqttMessage.DISCONNECT:

+			//we will never receive such a message from the broker

+			break;

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttConnack(MqttConnack receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Mqtt CONNACK message received.");

+

+		//if the return code of the Mqtt CONNACK message is not "Connection Accepted"

+		if (receivedMsg.getReturnCode() != MqttMessage.RETURN_CODE_CONNECTION_ACCEPTED){

+			GatewayLogger.log(GatewayLogger.ERROR, "GatewayMsgHandler ["+

+					Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+					"]/["+clientId+"] - Return Code of Mqtt CONNACK message it is not \"Connection Accepted\".");

+			GatewayLogger.log(GatewayLogger.ERROR, "GatewayMsgHandler ["+

+					Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+					"]/["+clientId+"] - Mqtt connection with the broker cannot be established. Gateway cannot start.");

+			System.exit(1);

+		}

+

+		//the connection was accepted by the broker

+		GatewayLogger.info("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Mqtt connection established.");

+

+		this.connected = true;

+

+		//initialize all available client interfaces for communication with clients

+		GatewayLogger.info("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Initializing all available Client interfaces...");

+

+		clientInterfacesVector = new Vector<ClientInterface>();

+		StringTokenizer st = new StringTokenizer(GWParameters.getClientIntString(),",");

+		boolean init = false;

+		while (st.hasMoreTokens()) {

+			String token = st.nextToken();

+			String clInte = token.substring(1, token.length()-1);

+			ClientInterface inter = null;

+			try {				

+				Class<?> cl = Class.forName(clInte);

+				inter = (ClientInterface)cl.newInstance();

+				inter.initialize();

+				GatewayLogger.info("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - "+inter.getClass().getName()+ " initialized.");

+				clientInterfacesVector.add(inter);

+				init = true;

+			}catch (IllegalAccessException e) {

+				GatewayLogger.warn("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to instantiate "+clInte+".");

+				e.printStackTrace();

+			}catch (InstantiationException e) {					

+				GatewayLogger.warn("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to instantiate "+clInte+".");

+				e.printStackTrace();

+			}catch (ClassNotFoundException e) {

+				GatewayLogger.warn("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to instantiate "+clInte+".");

+				e.printStackTrace();

+			}catch (MqttsException e) {

+				GatewayLogger.warn("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to initialize "+ inter.getClass().getName());

+				e.printStackTrace();

+			}

+		}	

+

+		if(!init){

+			GatewayLogger.error("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to initialize at least one Client interface.Gateway cannot start.");

+			System.exit(1);

+		}

+

+		GWParameters.setClientInterfacesVector(clientInterfacesVector);

+

+		//broadcast the Mqtts ADVERTISE message to the clients (whole network)

+		GatewayLogger.info("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Broadcasting initial Mqtts ADVERTISE message...");

+

+//		sendMqttsAdvertise();

+

+		GatewayLogger.info("-------- Mqtts Gateway started --------");

+

+		//Send a initial Mqtts PINGREQ message to the broker

+		sendMqttPingReq();

+

+		//set a keep alive timer for sending subsequent Mqtt PINGREQ messages to the broker

+		timer.register(gatewayAddress, ControlMessage.SEND_KEEP_ALIVE_MSG, GWParameters.getKeepAlivePeriod());

+	}

+

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPingResp(MqttPingResp receivedMsg) {

+		//		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PINGRESP message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPingReq(MqttPingReq receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PINGREQ message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttUnsuback(MqttUnsuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt UNSUBACK message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttSuback(MqttSuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt SUBACK message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPubComp(MqttPubComp receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PUBCOMP message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPubRel(MqttPubRel receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PUBREL message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPubRec(MqttPubRec receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PUBREC message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPuback(MqttPuback receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PUBACK message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/**

+	 * @param receivedMsg

+	 */

+	private void handleMqttPublish(MqttPublish receivedMsg) {

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtt PUBLISH message received.");

+

+		// TODO Auto-generated method stub

+

+	}

+

+	/******************************************************************************************/

+	/**                        HANDLING OF CONTROL MESSAGES AND TIMEOUTS	                **/

+	/****************************************************************************************/

+

+	/**

+	 * @param receivedMsg

+	 */

+	public void handleControlMessage(ControlMessage receivedMsg){

+		//get the type of the Control message and handle the message according to that type	

+		switch(receivedMsg.getMsgType()){

+		case ControlMessage.CONNECTION_LOST:

+			connectionLost();

+			break;	

+

+		case ControlMessage.WAITING_WILLTOPIC_TIMEOUT:

+			//we will never receive such a message 

+			break;

+

+		case ControlMessage.WAITING_WILLMSG_TIMEOUT:

+			//we will never receive such a message 

+			break;

+

+		case ControlMessage.WAITING_REGACK_TIMEOUT:

+			//we will never receive such a message 

+			break;

+

+		case ControlMessage.CHECK_INACTIVITY:

+			//ignore it

+			break;	

+

+		case ControlMessage.SEND_KEEP_ALIVE_MSG:

+			handleControlKeepAlive();

+			break;		

+

+		case ControlMessage.SHUT_DOWN:

+			shutDown();

+			break;			

+

+		default:

+			GatewayLogger.log(GatewayLogger.WARN, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Control message of unknown type \"" + receivedMsg.getMsgType()+"\" received.");

+			break;

+		}

+	}	

+

+	/**

+	 * 

+	 */

+	private void connectionLost(){

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Control CONNECTION_LOST message received.");

+

+		GatewayLogger.error("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - TCP/IP connection with the broker was lost.");

+

+		if (this.connected){	

+

+			//close the connection with the broker (if any)

+			brokerInterface.disconnect();

+

+			this.connected = false;

+

+			//generate a control message 

+			ControlMessage controlMsg = new ControlMessage();

+			controlMsg.setMsgType(ControlMessage.SHUT_DOWN);

+

+			//construct an "internal" message and put it to dispatcher's queue

+			//@see org.eclipse.paho.mqttsn.gateway.core.Message

+			Message msg = new Message(null);

+			msg.setType(Message.CONTROL_MSG);

+			msg.setControlMessage(controlMsg);

+			this.dispatcher.putMessage(msg);	

+		}else{

+			GatewayLogger.error("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed to establish Mqtt connection with the broker.Gateway cannot start.");

+			System.exit(1);

+		}

+	}

+

+

+

+	/**

+	 * 

+	 */

+	private void handleControlKeepAlive() {

+		//		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Control SEND_KEEP_ALIVE_MSG message received.");

+

+		//send a Mqtts PINGREQ to the broker

+		sendMqttPingReq();

+

+		//update the advertising period counter

+		advPeriodCounter = advPeriodCounter + GWParameters.getKeepAlivePeriod();

+		if (advPeriodCounter >= GWParameters.getAdvPeriod()){

+			//broadcast the Mqtts ADVERTISE message to the network

+//			sendMqttsAdvertise();			

+			advPeriodCounter = 0;

+		}

+

+		//update the clean up period counter

+		checkingCounter = checkingCounter + GWParameters.getKeepAlivePeriod();

+		if(checkingCounter >= GWParameters.getCkeckingPeriod ()){

+			//send a check timeout message to all ClientMsgHandlers

+			sendCheckInactivity();	

+			checkingCounter = 0;

+		}		

+	}

+

+

+	/**

+	 * 

+	 */

+	private void shutDown() {		

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Control SHUT_DOWN message received.");

+

+		//stop the reading thread of the BrokerInterface (if any)

+		//(this does not have any effect to the input and output streams which remain active)

+		brokerInterface.setRunning(false);

+

+		//construct a Mqtt DISCONNECT message

+		MqttDisconnect mqttDisconnect = new MqttDisconnect();

+

+		//send the Mqtt DISCONNECT message to the broker

+		//(don't bother if the sending of Mqtt DISCONNECT message to the broker was successful or not)

+		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt DISCONNECT message to the broker.");

+		try {

+			brokerInterface.sendMsg(mqttDisconnect);

+		} catch (MqttsException e) {

+			// do nothing

+		}

+

+		//close the connection with the broker

+		brokerInterface.disconnect();

+	}	

+

+

+	/******************************************************************************************/

+	/**                               OTHER METHODS              	                        **/

+	/****************************************************************************************/

+

+	/**

+	 * @throws MqttsException 

+	 * 

+	 */

+	public void connect() {

+		//construct a new Mqtt CONNECT message

+		MqttConnect mqttConnect = new MqttConnect();		

+		mqttConnect.setProtocolName(GWParameters.getProtocolName());

+		mqttConnect.setProtocolVersion (GWParameters.getProtocolVersion());

+		mqttConnect.setWillRetain (GWParameters.isRetain());

+		mqttConnect.setWillQoS (GWParameters.getWillQoS());

+		mqttConnect.setWill (GWParameters.isWillFlag());	

+		mqttConnect.setCleanStart (GWParameters.isCleanSession());

+		mqttConnect.setKeepAlive(GWParameters.getKeepAlivePeriod());

+		mqttConnect.setClientId (clientId);

+		mqttConnect.setWillTopic (GWParameters.getWillTopic());

+		mqttConnect.setWillMessage (GWParameters.getWillMessage());

+

+		//		GatewayLogger.info("** will= " + mqttConnect.isWill() + 

+		//				" willTopic= " + mqttConnect.getWillTopic() +

+		//				", willMessage= " + mqttConnect.getWillMessage());

+

+		GatewayLogger.info("GatewayMsgHandler ["+

+				Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+				"]/["+clientId+"] - Establishing MQTT connection with the broker...");

+

+		//		GatewayLogger.log(GatewayLogger.INFO, "GatewayMsgHandler ["+Utils.hexString(this.gatewayAddress.getAddress())+"]/["+clientId+"] - Sending Mqtt CONNECT message to the broker.");

+		//send the Mqtt CONNECT message to the broker

+		try {

+			brokerInterface.sendMsg(mqttConnect);

+		} catch (MqttsException e) {

+			e.printStackTrace();

+			GatewayLogger.error("GatewayMsgHandler ["+

+					Utils.hexString(GWParameters.getGatewayAddress().getAddress())+

+					"]/["+clientId+"] - Failed to establish Mqtt connection with the broker. Gateway cannot start.");

+			System.exit(1);

+		}

+	}

+

+

+	/**

+	 * 

+	 */

+	private void sendMqttPingReq() {

+		//construct a Mqtt PINGREQ message

+		MqttPingReq pingreq = new MqttPingReq();

+

+		//		GatewayLogger.info("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Sending Mqtt PINGREQ message to the broker.");

+

+		//send the Mqtt PINGREQ message to the broker

+		try {

+			brokerInterface.sendMsg(pingreq);

+		} catch (MqttsException e) {			

+			e.printStackTrace();

+			GatewayLogger.error("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Failed sending Mqtts PINGREQ message to the broker.");			

+			connectionLost();

+		}				

+	}

+

+

+	/**

+	 * 

+	 */

+//	private void sendMqttsAdvertise() {

+//		MqttsAdvertise adv = new MqttsAdvertise();

+//		adv.setGwId(GWParameters.getGwId());

+//		adv.setDuration(GWParameters.getAdvPeriod());

+//		

+//		//broadcast the message to all available interfaces

+//		Vector interfaces = GWParameters.getClientInterfaces();

+//		for(int i = 0; i < interfaces.size(); i++){

+//			ClientInterface inter = (ClientInterface) interfaces.get(i);

+//			inter.broadcastMsg(adv);

+//		}	

+//		

+//		GatewayLogger.info("GatewayMsgHandler ["+Utils.hexString(GWParameters.getGatewayAddress().getAddress())+"]/["+clientId+"] - Mqtts ADVERTISE message was broadcasted to the network.");

+//	}

+	

+	

+	/**

+	 * 

+	 */

+	private void sendCheckInactivity() {

+		//generate a control message 

+		ControlMessage controlMsg = new ControlMessage();

+		controlMsg.setMsgType(ControlMessage.CHECK_INACTIVITY);

+

+		//generate an "internal" message

+		//@see org.eclipse.paho.mqttsn.gateway.core.Message

+

+		//addressed to all ClientMsgHandlers

+		Message msg = new Message(null);

+

+		msg.setType(Message.CONTROL_MSG);

+		msg.setControlMessage(controlMsg);

+		this.dispatcher.putMessage(msg);		

+	}

+

+	/**

+	 * @param topicName

+	 */

+	//	private void sendMqttSubscribe(String topicName){

+

+	//	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/MsgHandler.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/MsgHandler.java
new file mode 100644
index 0000000..f638d52
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/MsgHandler.java
@@ -0,0 +1,47 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.core;

+

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+

+public abstract class MsgHandler {

+		

+	/**

+	 * 

+	 */

+	public abstract void initialize();

+	

+	

+	/**

+	 * @param msg

+	 */

+	public abstract void handleMqttsMessage(MqttsMessage msg);

+	

+	

+	/**

+	 * @param msg

+	 */

+	public abstract void handleMqttMessage(MqttMessage msg);

+	

+	

+	/**

+	 * @param msg

+	 */

+	public abstract void handleControlMessage(ControlMessage msg);

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/TopicMappingTable.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/TopicMappingTable.java
new file mode 100644
index 0000000..7b70c8a
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/core/TopicMappingTable.java
@@ -0,0 +1,117 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.core;

+

+import java.util.Hashtable;

+import java.util.Iterator;

+

+import org.eclipse.paho.mqttsn.gateway.utils.GWParameters;

+

+public class TopicMappingTable {

+

+	private Hashtable<Integer, String> topicIdTable;

+

+	public TopicMappingTable(){

+		topicIdTable = new Hashtable<Integer, String>();

+	}

+

+

+	public void initialize() {

+		Iterator<?> iter = GWParameters.getPredefTopicIdTable().keySet().iterator();

+		Iterator<?> iterVal = GWParameters.getPredefTopicIdTable().values().iterator();

+

+		Integer topicId;

+		String topicName;

+		while (iter.hasNext()) {

+			topicId = (Integer)iter.next();	

+			topicName = (String)iterVal.next();

+			topicIdTable.put(topicId, topicName);

+		}

+	}

+

+	/**

+	 * @param topicId

+	 * @param topicName

+	 */

+	public void assignTopicId(int topicId, String topicName) {

+		topicIdTable.put(new Integer (topicId), topicName);

+	}

+

+	public String getTopicName(int topicId) {

+		return (String)topicIdTable.get(new Integer(topicId));

+	}

+

+	/**

+	 * @param topicName

+	 * @return

+	 */

+	public int getTopicId(String topicName) {

+		Iterator<Integer> iter = topicIdTable.keySet().iterator();

+		Iterator<String> iterVal = topicIdTable.values().iterator();

+		Integer ret = new Integer(0);

+		while (iter.hasNext()) {

+			Integer topicId = (Integer)iter.next();			

+			String tname = (String)(iterVal.next());

+			if(tname.equals(topicName)) {

+				ret = topicId;

+				break;

+			}

+		}

+		return ret.intValue();

+	}

+

+	/**

+	 * @param topicId

+	 */

+	public void removeTopicId(int topicId) {

+		topicIdTable.remove(new Integer(topicId));		

+	}

+

+

+	/**

+	 * @param topicName

+	 */

+	public void removeTopicId(String topicName) {

+		Iterator<Integer> iter = topicIdTable.keySet().iterator();

+		Iterator<String> iterVal = topicIdTable.values().iterator();

+		while (iter.hasNext()) {

+			Integer topicId = (Integer)iter.next();			

+			String tname = (String)(iterVal.next());

+

+			//don't remove predefined topic ids

+			if(tname.equals(topicName) && topicId.intValue() > GWParameters.getPredfTopicIdSize()) {

+				topicIdTable.remove(topicId);

+				break;

+			}

+		}

+	}

+

+

+	/**

+	 * 

+	 * Utility method. Prints the content of this mapping table

+	 */

+	public void printContent(){

+		Iterator<Integer> iter = topicIdTable.keySet().iterator();

+		Iterator<String> iterVal = topicIdTable.values().iterator();

+		while (iter.hasNext()) {

+			Integer topicId = (Integer)iter.next();			

+			String tname = (String)(iterVal.next());

+			System.out.println(topicId+" = "+ tname);

+		}		

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/exceptions/MqttsException.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/exceptions/MqttsException.java
new file mode 100644
index 0000000..c24c179
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/exceptions/MqttsException.java
@@ -0,0 +1,40 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 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.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/Message.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/Message.java
new file mode 100644
index 0000000..11bea77
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/Message.java
@@ -0,0 +1,106 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages;

+

+import org.eclipse.paho.mqttsn.gateway.client.ClientInterface;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtt.MqttMessage;

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.MqttsMessage;

+import org.eclipse.paho.mqttsn.gateway.utils.Address;

+

+

+/**

+ * This object represents an "internal" message that "wraps" a Mqtts, a Mqtt

+ * or a Control message.It is generated by the BroketInterface, any ClientInterface, the TimerService

+ * and the MsgHandler (GatewayMsgHandler or ClientMsgHandler) and then is added in Dispatcher's queue.

+ * In the case of Mqtts message carries also the client interface in which

+ * MsgHandler will respond in the future.In all cases carries the Address field in order to 

+ * uniquely identify the ClientMsgHandler or GatewayMsgHandler.If this filed does not exist,

+ * the encapsulated message (Mqtts, Mqtt or Control) is addressed to all MsgHandlers.

+ * 

+ * @see org.eclipse.paho.mqttsn.gateway.core.Dispatcher

+ * @see org.eclipse.paho.mqttsn.gateway.core.MsgHandler

+ * @see org.eclipse.paho.mqttsn.gateway.core.ClientMsgHandler

+ * @see org.eclipse.paho.mqttsn.gateway.core.GatewayMsgHandler

+ *  

+ *

+ */

+public class Message {

+

+	public static final int MQTTS_MSG = 1;

+	public static final int MQTT_MSG = 2;

+	public static final int CONTROL_MSG = 3;

+

+

+	private final Address address;

+	private int type;

+

+	private MqttsMessage mqttsMessage = null;

+	private MqttMessage mqttMessage = null;

+	private ControlMessage controlMessage = null;

+

+	private ClientInterface clientInterface = null; 

+

+

+	public Message(Address address) {

+		this.address = address;

+	}

+

+	public Address getAddress() {

+		return address;

+	}

+

+	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 MqttMessage getMqttMessage() {

+		return mqttMessage;

+	}

+

+	public void setMqttMessage(MqttMessage mqttMessage) {

+		this.mqttMessage = mqttMessage;

+	}

+

+	public ControlMessage getControlMessage() {

+		return controlMessage;

+	}

+

+	public void setControlMessage(ControlMessage controlMessage) {

+		this.controlMessage = controlMessage;

+	}

+

+	public ClientInterface getClientInterface() {

+		return clientInterface;

+	}

+

+	public void setClientInterface(ClientInterface clientInterface) {

+		this.clientInterface = clientInterface;

+	};	

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/control/ControlMessage.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/control/ControlMessage.java
new file mode 100644
index 0000000..a76d72b
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/control/ControlMessage.java
@@ -0,0 +1,43 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 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.gateway.messages.control;

+

+public class ControlMessage {

+

+	//Control message types	

+	public static final int CONNECTION_LOST     		= 1;

+	public static final int WAITING_WILLTOPIC_TIMEOUT 	= 2;

+	public static final int WAITING_WILLMSG_TIMEOUT 	= 3;

+	public static final int WAITING_REGACK_TIMEOUT 	    = 4;

+	public static final int CHECK_INACTIVITY			= 5;

+	public static final int SEND_KEEP_ALIVE_MSG			= 6;

+	public static final int SHUT_DOWN					= 7;

+

+	public ControlMessage(){}

+

+	private int msgType;

+

+	public int getMsgType() {

+		return msgType;

+	}

+

+	public void setMsgType(int msgType) {

+		this.msgType = msgType;

+	}

+

+

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnack.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnack.java
new file mode 100644
index 0000000..901a09a
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnack.java
@@ -0,0 +1,69 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+/**

+ * This object represents a Mqtt CONNACK message.

+ * 

+ *

+ */

+public class MqttConnack extends MqttMessage{

+

+	//Mqtt CONNACK fields

+	private boolean	topicNameCompression = false; //not used

+	private int returnCode;

+

+	/**

+	 * MqttConack constructor.Sets the appropriate message type. 

+	 */

+	public MqttConnack() {

+		msgType = MqttMessage.CONNACK;

+	}

+

+	/**

+	 * MqttConack constructor.Sets the appropriate message type and constructs 

+	 * a Mqtt CONNACK message from a received byte array.

+	 * @param data: The buffer that contains the CONNACK message.

+	 */

+	public MqttConnack(byte[] data) {

+		msgType = MqttMessage.CONNACK;

+		returnCode = (data[3] & 0xFF);

+	}

+

+	/**

+	 * Method to convert this message to byte array for transmission.

+	 * (Don't needed in the GW)

+	 */

+	public byte[] toBytes() {

+		int length = 4;

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		data [2] = ((topicNameCompression) ? (byte)0x01 : (byte)0x00);

+		data [3] = (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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnect.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnect.java
new file mode 100644
index 0000000..ca6a09b
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttConnect.java
@@ -0,0 +1,160 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+/**

+ * This object represents a Mqtt CONNECT message.

+ * 

+ *

+ */

+public class MqttConnect extends MqttMessage{

+

+	//Mqtt CONNECT fields

+	private String protocolName;

+	private int protocolVersion;

+	private boolean cleanStart;

+	private boolean topicNameCompression = false;//not used

+	private int keepAlive;

+	private boolean will;

+	private int willQoS;

+	private boolean willRetain;

+	private String willTopic;

+	private String willMessage;

+	private String clientId;

+

+	/**

+	 * MqttConnect constructor.Sets the appropriate message type. 

+	 */

+	public MqttConnect() {

+		msgType = MqttMessage.CONNECT;

+	}

+

+	/**

+	 * This method is not needed in the GW

+	 */

+	public MqttConnect(byte[] data) {}

+

+

+	/**

+	 * Method to convert this message to byte array for transmission

+	 * @return A byte array containing the CONNECT message as it should appear on the wire.

+	 */

+	public byte[] toBytes() {

+		int pos = 0; 

+		byte[] data = new byte[MAX_CLIENT_ID_LENGTH + 19]; 

+		data[pos++] = (byte)((msgType << 4) & 0xF0); 

+		byte[] bytestring = Utils.StringToUTF(protocolName);

+		System.arraycopy(bytestring, 0, data, pos, bytestring.length);

+		pos += bytestring.length;

+		data[pos++] = (byte) protocolVersion;

+

+		byte compSub = ((topicNameCompression) ? (byte) 0x01 : (byte)0x00); // bit 0

+		byte clean = ((cleanStart) ? (byte) 0x02 : (byte) 0x00); // bit 1

+		byte theWill = (will) ? (byte) (((willRetain) ? 0x20 : 0x00) | // bit 5

+				(byte) ((willQoS & 0x03) << 3) | // bit 4 & 3

+				0x04 // bit 2

+				) : (byte) 0x00;

+		data[pos++] = (byte) (compSub | clean | theWill); // combine the bits

+		/* KeepAlive field */

+		data[pos++] = (byte) (keepAlive / 256); // MSB

+		data[pos++] = (byte) (keepAlive % 256); // LSB

+		// Client Id

+		bytestring = Utils.StringToUTF(clientId);

+		System.arraycopy(bytestring, 0, data, pos, bytestring.length);

+		pos += bytestring.length;

+		// Check if we want a will

+		if (will) {

+			// Add 'Will' topic

+			byte[] topicbytes = Utils.StringToUTF(willTopic);

+			// Add 'Will' data

+			byte[] msgbytes = Utils.StringToUTF(willMessage);

+			data = Utils.concatArray(Utils.concatArray(data,

+					0, pos, topicbytes, 0, topicbytes.length), msgbytes);

+			pos += topicbytes.length + msgbytes.length;

+		}

+		data = Utils.SliceByteArray(data, 0, pos);

+		data = encodeMsgLength(data); // add Remaining length field

+		return data;

+	}

+

+

+	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 boolean isCleanStart() {

+		return cleanStart;

+	}

+	public void setCleanStart(boolean cleanStart) {

+		this.cleanStart = cleanStart;

+	}

+	public int getKeepAlive() {

+		return keepAlive;

+	}

+	public void setKeepAlive(int keepAlive) {

+		this.keepAlive = keepAlive;

+	}

+	public boolean isWill() {

+		return will;

+	}

+	public void setWill(boolean will) {

+		this.will = will;

+	}

+	public int getWillQoS() {

+		return willQoS;

+	}

+	public void setWillQoS(int willQoS) {

+		this.willQoS = willQoS;

+	}

+	public boolean isWillRetain() {

+		return willRetain;

+	}

+	public void setWillRetain(boolean willRetain) {

+		this.willRetain = willRetain;

+	}

+	public String getWillTopic() {

+		return willTopic;

+	}

+	public void setWillTopic(String willTopic) {

+		this.willTopic = willTopic;

+	}

+	public String getWillMessage() {

+		return willMessage;

+	}

+	public void setWillMessage(String willMessage) {

+		this.willMessage = willMessage;

+	}

+	public String getClientId() {

+		return clientId;

+	}

+

+	public void setClientId(String aClientId) {

+		clientId = aClientId;

+	}

+

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttDisconnect.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttDisconnect.java
new file mode 100644
index 0000000..42640c5
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttDisconnect.java
@@ -0,0 +1,50 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt DISCONNECT message.

+ * 

+ *

+ */

+public class MqttDisconnect extends MqttMessage{

+

+	/**

+	 * MqttDisconnect constructor.Sets the appropriate message type. 

+	 */

+	public MqttDisconnect() {

+		msgType = MqttMessage.DISCONNECT;

+	}

+

+	/**

+	 * This method is not needed in the GW

+	 */

+	public MqttDisconnect(byte[] data) {}

+

+	/**

+	 * Method to convert this message to 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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x00;//add Remaining length field

+		return data;

+	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttMessage.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttMessage.java
new file mode 100644
index 0000000..f02b293
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttMessage.java
@@ -0,0 +1,120 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+/**

+ * This object represents a Mqtt message. It is subclassed

+ * to create the appropriate Mqtt Message.

+ * 

+ * 

+ * Parts of code on Mqtt message classes were imported from the similar classes on

+ * com.ibm.mqttclient.ia92 package

+ *

+ */

+public abstract class MqttMessage {

+

+	//Mqtt messages types

+	public final static int CONNECT 			= 1;

+	public final static int CONNACK 			= 2;

+	public final static int PUBLISH 			= 3;

+	public final static int PUBACK 				= 4;

+	public final static int PUBREC 				= 5;

+	public final static int PUBREL 				= 6;

+	public final static int PUBCOMP 			= 7;

+	public final static int SUBSCRIBE 			= 8;

+	public final static int SUBACK 				= 9;

+	public final static int UNSUBSCRIBE 	 	= 10;

+	public final static int UNSUBACK 			= 11;

+	public final static int PINGREQ 			= 12;

+	public final static int PINGRESP 			= 13;

+	public final static int DISCONNECT 			= 14;

+	

+	// Mqtt message type

+	protected int msgType;

+

+	public final static int RETURN_CODE_CONNECTION_ACCEPTED = 0;

+

+	// client id restriction

+	public static final int    MAX_CLIENT_ID_LENGTH = 23;

+	

+	

+	/**

+	 * MqttMessage default constructor.

+	 */

+	public MqttMessage() {}

+	

+	

+	/**

+	 * This method calculates the length of a Mqtt message and encodes it 

+	 * in the fixed header.

+	 */	

+	protected byte[] encodeMsgLength(byte[] data) {		

+		int size = data.length - 1; 

+		int pos = 0;				

+		byte[] tmp = new byte[4]; 

+		// Encode remaining length field in tmp[]

+		do {

+			int digit = size % 128;

+			size = size / 128;

+			if (size > 0) {

+				digit = digit | 0x80;

+			}

+			tmp[pos++]=(byte) digit;

+		} while (size > 0);

+		byte[] buffer = new byte[data.length + pos];

+		buffer[0] = data[0];								// Fixed Hdr

+		System.arraycopy(tmp, 0, buffer, 1, pos);			// add the MsgLength bytes

+		System.arraycopy(data,1,buffer,pos+1,data.length-1);// add the rest of Message

+		data = buffer;

+		return data;

+	}

+	

+	/**

+	 * This method decodes the Remaining length field of a Mqtt message and 

+	 * returns the number of the remaining bytes of the message.

+	 */	

+	protected long decodeMsgLength(byte[] data) {		

+		byte digit;

+		long msgLength = 0;

+		int multiplier = 1;

+		int offset = 1;

+		do {

+			// Now read msgLength bytes

+			digit = (byte)data[offset];

+			msgLength += ((digit & 0x7F) * multiplier);

+			multiplier *= 128;

+			offset++;

+		} while ((digit & 0x80) != 0);		

+		return msgLength;

+	}

+

+

+	/**

+	 * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingReq.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingReq.java
new file mode 100644
index 0000000..20b79f0
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingReq.java
@@ -0,0 +1,53 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PINGREQ message.

+ * 

+ *

+ */

+public class MqttPingReq extends MqttMessage{

+

+	/**

+	 * MqttPingReq constructor.Sets the appropriate message type. 

+	 */

+	public MqttPingReq() {

+		msgType = MqttMessage.PINGREQ;

+	}

+	

+	

+	/**

+	 * MqttPingReq constructor.Sets the appropriate message type. 

+	 */

+	public MqttPingReq(byte[] data) {

+		msgType = MqttMessage.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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x00;//add Remaining length fields

+		return data;

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingResp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingResp.java
new file mode 100644
index 0000000..22745a1
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPingResp.java
@@ -0,0 +1,53 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PINGRESP message.

+ * 

+ *

+ */

+public class MqttPingResp extends MqttMessage{

+

+	/**

+	 * MqttPingResp constructor.Sets the appropriate message type. 

+	 */

+	public MqttPingResp() {

+		msgType = MqttMessage.PINGRESP;

+	}

+	

+	

+	/**

+	 * MqttPingResp constructor.Sets the appropriate message type. 

+	 */

+	public MqttPingResp(byte[] data) {

+		msgType = MqttMessage.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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x00;//add Remaining length fields

+		return data;

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubComp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubComp.java
new file mode 100644
index 0000000..583d9c5
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubComp.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PUBCOMP message.

+ * 

+ *

+ */

+public class MqttPubComp extends MqttMessage{

+

+	//Mqtt PUBCOMP fields

+	private int msgId;

+

+	/**

+	 * MqttPubcomp constructor.Sets the appropriate message type. 

+	 */

+	public MqttPubComp() {

+		msgType = MqttMessage.PUBCOMP;

+	}

+

+	/**

+	 * MqttPubcomp constructor.Sets the appropriate message type and constructs

+	 * a Mqtt PUBCOMP message from a received byte array.

+	 * @param data: The buffer that contains the PUBCOMP message.

+	 */

+	public MqttPubComp(byte[] data) {

+		msgType = MqttMessage.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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRec.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRec.java
new file mode 100644
index 0000000..d9222e6
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRec.java
@@ -0,0 +1,69 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PUBREC message.

+ * 

+ *

+ */

+public class MqttPubRec extends MqttMessage{

+

+	//Mqtt PUBREC fields

+	private int msgId;

+

+	/**

+	 * MqttPubRec constructor.Sets the appropriate message type. 

+	 */

+	public MqttPubRec() {

+		msgType = MqttMessage.PUBREC;

+	}

+

+	/**

+	 * MqttPubRec constructor.Sets the appropriate message type and constructs

+	 * a Mqtt PUBREC message from a received byte array.

+	 * @param data: The buffer that contains the PUBREC message.

+	 */

+	public MqttPubRec(byte[] data) {

+		msgType = MqttMessage.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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRel.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRel.java
new file mode 100644
index 0000000..9760ea0
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPubRel.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PUBREL message.

+ * 

+ */

+public class MqttPubRel extends MqttMessage{

+	

+	//Mqtt PUBREL fields

+	private int msgId;

+	

+	/**

+	 * MqttPubRel constructor.Sets the appropriate message type. 

+	 */

+	public MqttPubRel() {

+		msgType = MqttMessage.PUBREL;

+	}

+	

+	/**

+	 * MqttPubRel constructor.Sets the appropriate message type and constructs

+	 * a Mqtt PUBREL message from a received byte array.

+	 * @param data: The buffer that contains the PUBREL message.

+	 */

+	public MqttPubRel(byte[] data) {

+		msgType = MqttMessage.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)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPuback.java
new file mode 100644
index 0000000..11a6320
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPuback.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt PUBACK message.

+ * 

+ *

+ */

+public class MqttPuback extends MqttMessage{

+

+	//Mqtt PUBACK fields

+	private int msgId;

+

+	/**

+	 * MqttPuback constructor.Sets the appropriate message type. 

+	 */

+	public MqttPuback() {

+		msgType = MqttMessage.PUBACK;

+	}

+

+	/**

+	 * MqttPuback constructor.Sets the appropriate message type and constructs

+	 * a Mqtt PUBACK message from a received byte array.

+	 * @param data: The buffer that contains the PUBACK message.

+	 */

+	public MqttPuback(byte[] data){

+		msgType = MqttMessage.PUBACK;

+		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 PUBACK message as it should appear on the wire.

+	 */

+	public byte[] toBytes() {

+		int length = 4;

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPublish.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPublish.java
new file mode 100644
index 0000000..fb4a3aa
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttPublish.java
@@ -0,0 +1,148 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+/**

+ * This object represents a Mqtt PUBLISH message.

+ * 

+ *

+ */

+public class MqttPublish extends MqttMessage{

+

+	//Mqtt PUBLISH fields

+	private boolean dup;

+	private int qos;

+	private boolean retain;

+	private String topicName;

+	private int msgId;

+	private byte[] payload;

+

+	/**

+	 * MqttPublish constructor.Sets the appropriate message type. 

+	 */

+	public MqttPublish() {

+		msgType = MqttMessage.PUBLISH;	

+	}

+

+	/**

+	 * MqttPublish constructor.Sets the appropriate message type and constructs

+	 * a Mqtt PUBLISH message from a received byte array.

+	 * @param data: The buffer that contains the PUBLISH message.

+	 */

+	public MqttPublish(byte[] data) {

+		msgType = MqttMessage.PUBLISH;	

+		dup = ((data[0] & 0x08) >> 3 != 0);

+		qos = (data[0] & 0x06) >> 1;

+		retain = ((data[0] & 0x01) != 0);		

+

+		long remainingBytes = decodeMsgLength(data);//the number of remaining bytes after the fixed header

+		int fixedHeaderLength = (int) (data.length - remainingBytes);//the length of the fixed header

+		topicName = Utils.UTFToString(data, fixedHeaderLength);

+

+		if (qos > 0) {

+			msgId = ((data[fixedHeaderLength + 2 + topicName.length()] & 0xFF) << 8) + (data[fixedHeaderLength + 2 + topicName.length() + 1] & 0xFF);

+			payload = Utils.SliceByteArray(data, fixedHeaderLength + topicName.length() + 4, data.length - (fixedHeaderLength + topicName.length() + 4));

+		} else {

+			payload = Utils.SliceByteArray(data, fixedHeaderLength + topicName.length() + 2, data.length - (fixedHeaderLength + topicName.length() + 2));

+		}

+	}

+

+	/**

+	 * 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() {

+		byte[] data;

+		byte[] byteString = Utils.StringToUTF(topicName);

+		if ( qos > 0 ) {

+			data = new byte[byteString.length + 3 + payload.length];

+		} else {

+			// No message id in a QoS 0 message

+			data = new byte[byteString.length + 1 + payload.length];

+		}

+

+		data[0] = (byte)((this.msgType << 4) & 0xF0);//msg type

+		byte bdup = (byte) ((dup) ? 0x08 : 0x00);//dup flag

+		byte bqos = (byte) ((qos & 0x03) << 1);//qos

+		byte bret = (byte) ((retain) ? 0x01 : 0x00);//retain

+

+		data[0] = (byte) (data[0] | bqos | bret | bdup);//1st byte completed

+

+		int pos = 1;	

+		System.arraycopy(byteString,0,data,pos,byteString.length);//attach the topic name

+		pos+=byteString.length;

+

+		if (qos > 0) {

+			int msgId = getMsgId();

+			data[pos++] = (byte) (msgId / 256); // MSB

+			data[pos++] = (byte) (msgId % 256); // LSB

+		}  

+		System.arraycopy(payload,0,data,pos,payload.length);//attach the payload

+		data = encodeMsgLength(data);	// add Remaining Length field

+		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 String getTopicName() {

+		return topicName;

+	}

+

+	public void setTopicName(String topicName) {

+		this.topicName = topicName;

+	}

+

+	public int getMsgId() {

+		return msgId;

+	}

+

+	public void setMsgId(int msgId) {

+		this.msgId = msgId;

+	}

+

+	public byte[] getPayload() {

+		return payload;

+	}

+

+	public void setPayload(byte[] payload) {

+		this.payload = payload;

+	}	

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSuback.java
new file mode 100644
index 0000000..6115871
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSuback.java
@@ -0,0 +1,81 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt SUBACK message.

+ * 

+ */

+public class MqttSuback extends MqttMessage {

+

+	//Mqtt SUBACK fields

+	private int msgId;

+	private int grantedQoS; //supports only one topic name at the time (as with mqtts) not an array

+

+

+	/**

+	 * MqttSuback constructor.Sets the appropriate message type. 

+	 */

+	public MqttSuback() {

+		msgType = MqttMessage.SUBACK;

+	}

+

+	/**

+	 * MqttSuback constructor.Sets the appropriate message type and constructs 

+	 * a Mqtt SUBACK message from a received byte array.

+	 * @param data: The buffer that contains the SUBACK message.

+	 */

+	public MqttSuback(byte[] data) {

+		msgType = MqttMessage.SUBACK;

+		msgId = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);

+		grantedQoS = (data[4] & 0x03);

+	}

+

+	/**

+	 * Method to convert this message to byte array for transmission.

+	 * @return A byte array containing the UNSUBACK message as it should appear on the wire.

+	 * (Don't needed in the GW)

+	 */

+	public byte[] toBytes() {

+		int length = 5;

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x03;//add Remaining length fields

+		data [2] = (byte)((msgId >> 8) & 0xFF);

+		data [3] = (byte) (msgId & 0xFF);

+		data [4] = (byte)(grantedQoS & 0xFF);		

+		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;

+	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSubscribe.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSubscribe.java
new file mode 100644
index 0000000..176e7e1
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttSubscribe.java
@@ -0,0 +1,102 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+/**

+ * This object represents a Mqtt SUBSCRIBE message.

+ * 

+ *

+ */

+public class MqttSubscribe extends MqttMessage{

+

+	//Mqtt SUBSCRIBE fields

+	private boolean dup;

+//	private final int qos = 1;//qos for the message itself is set to 1 

+	private int msgId;

+	public String topicName;//supports only one topic name at the time (as mqtts) not an array

+	public int	requestedQoS;

+

+

+	/**

+	 * MqttSubscribe constructor.Sets the appropriate message type. 

+	 */

+	public MqttSubscribe() {

+		msgType = MqttMessage.SUBSCRIBE;

+	}

+

+	/**

+	 * MqttSubscribe constructor.Sets the appropriate message type and constructs 

+	 * a Mqtt SUBSCRIBE message from a received byte array.

+	 * @param data: The buffer that contains the SUBSCRIBE message.

+	 * (Don't needed in the GW)

+	 */

+	public MqttSubscribe(byte[] data) {}

+

+

+	/**

+	 * 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.

+	 */

+	public byte[] toBytes() {

+		int length = topicName.length() + 6;//1st byte plus 2 bytes for utf encoding, 2 for msgId and 1 for requested qos

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);	

+		data [0] |= 0x02; //insert qos = 1

+		data [1] = (byte)((msgId >> 8) & 0xFF);

+		data [2] = (byte) (msgId & 0xFF);

+

+		byte[] utfEncodedTopicName = Utils.StringToUTF(topicName);

+		System.arraycopy(utfEncodedTopicName, 0, data, 3, utfEncodedTopicName.length);

+		data[length-1] = (byte)(requestedQoS);//insert requested qos

+		data = encodeMsgLength(data);	// add Remaining Length field

+		return data;

+	}

+

+	public String getTopicName() {

+		return topicName;

+	}

+

+	public void setTopicName(String topicName) {

+		this.topicName = topicName;

+	}

+

+	public int getRequestedQoS() {

+		return requestedQoS;

+	}

+

+	public void setRequestedQoS(int requestedQoS) {

+		this.requestedQoS = requestedQoS;

+	}

+

+	public boolean isDup() {

+		return dup;

+	}

+

+	public void setDup(boolean dup) {

+		this.dup = dup;

+	}

+

+	public int getMsgId() {

+		return msgId;

+	}

+

+	public void setMsgId(int msgId) {

+		this.msgId = msgId;

+	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsuback.java
new file mode 100644
index 0000000..99590f7
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsuback.java
@@ -0,0 +1,69 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+

+/**

+ * This object represents a Mqtt UNSUBACK message.

+ * 

+ *

+ */

+public class MqttUnsuback extends MqttMessage{

+

+	//Mqtt UNSUBACK fields

+	private int msgId;

+	

+	/**

+	 * MqttUnsuback constructor.Sets the appropriate message type. 

+	 */

+	public MqttUnsuback() {

+		msgType = MqttMessage.UNSUBACK;

+	}

+	

+	/**

+	 * MqttUnsuback constructor.Sets the appropriate message type and constructs 

+	 * a Mqtt UNSUBACK message from a received byte array.

+	 * @param data: The buffer that contains the UNSUBACK message.

+	 */

+	public MqttUnsuback(byte[] data) {

+		msgType = MqttMessage.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.

+	 * (Don't needed in the GW)

+	 */

+	public byte[] toBytes() {

+		int length = 4;

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);

+		data [1] = (byte)0x02;//add Remaining length fields

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsubscribe.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsubscribe.java
new file mode 100644
index 0000000..848b39f
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtt/MqttUnsubscribe.java
@@ -0,0 +1,92 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtt;

+

+import org.eclipse.paho.mqttsn.gateway.utils.Utils;

+

+

+/**

+ * This object represents a Mqtt UNSUBSCRIBE message.

+ * 

+ */

+public class MqttUnsubscribe extends MqttMessage{

+	

+

+	// Mqtt UNSUBSCRIBE fields

+	private boolean dup;

+//	private int qos = 1;//qos for the message itself is set to 1 

+	private int msgId;

+	private String topicName;//supports only one topic name at the time (as mqtts) not an array

+	

+	/**

+	 * MqttUnsubscribe constructor.Sets the appropriate message type. 

+	 */

+	public MqttUnsubscribe() {

+		msgType = MqttMessage.UNSUBSCRIBE;

+	}

+	

+	/**

+	 * MqttUnsubscribe constructor.Sets the appropriate message type and constructs 

+	 * a Mqtt UNSUBSCRIBE message from a received byte array.

+	 * @param data: The buffer that contains the UNSUBSCRIBE message.

+	 * (Don't needed in the GW)

+	 */

+	public MqttUnsubscribe(byte[] data, int offset) {}

+	

+	

+	/**

+	 * 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.

+	 */

+	public byte[] toBytes() {

+		int length = topicName.length() + 5;//1st byte plus 2 bytes for utf encoding and 2 for msgId

+		byte[] data = new byte[length];

+		data [0] = (byte)((msgType << 4) & 0xF0);	

+		data [0] |= 0x02; //insert qos = 1

+		data [1] = (byte)((msgId >> 8) & 0xFF);

+		data [2] = (byte) (msgId & 0xFF);

+		

+		byte[] utfEncodedTopicName = Utils.StringToUTF(topicName);

+		System.arraycopy(utfEncodedTopicName, 0, data, 3, utfEncodedTopicName.length);

+		data = encodeMsgLength(data);	// add Remaining Length field

+		return data;

+	}

+

+	public boolean isDup() {

+		return dup;

+	}

+

+	public void setDup(boolean dup) {

+		this.dup = dup;

+	}

+

+	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;

+	}

+}

diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsAdvertise.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsAdvertise.java
new file mode 100644
index 0000000..f83e140
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsAdvertise.java
@@ -0,0 +1,79 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnack.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnack.java
new file mode 100644
index 0000000..b74da38
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnack.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import org.eclipse.paho.mqttsn.gateway.messages.mqtts.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnect.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnect.java
new file mode 100644
index 0000000..b76f0c9
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsConnect.java
@@ -0,0 +1,148 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+

+import org.eclipse.paho.mqttsn.gateway.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)0x00;  // 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsDisconnect.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsDisconnect.java
new file mode 100644
index 0000000..122cdea
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsDisconnect.java
@@ -0,0 +1,53 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsGWInfo.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsGWInfo.java
new file mode 100644
index 0000000..4bc0971
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsGWInfo.java
@@ -0,0 +1,66 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * This object represents a Mqtts GWINFO message.

+ * 

+ */

+public class MqttsGWInfo extends MqttsMessage {

+	

+	//Mqtts GWINFO fields

+	private int gwId;

+

+	/**

+	 * 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);

+	}

+

+

+	/**

+	 * 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;

+		byte[] data = new byte[length];

+		data[0] = (byte)length;

+		data[1] = (byte)msgType;

+		data[2] = (byte)gwId;			

+		return data;

+	}

+	

+	public int getGwId() {

+		return gwId;

+	}

+

+	public void setGwId(int gwId) {

+		this.gwId = gwId;

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsMessage.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsMessage.java
new file mode 100644
index 0000000..6cb8b7d
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsMessage.java
@@ -0,0 +1,91 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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;

+	

+	public static final int ENCAPSMSG       = 0xFE;

+	

+	//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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingReq.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingReq.java
new file mode 100644
index 0000000..ea7dc48
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingReq.java
@@ -0,0 +1,54 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingResp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingResp.java
new file mode 100644
index 0000000..e90833a
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPingResp.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubComp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubComp.java
new file mode 100644
index 0000000..b146c2e
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubComp.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRec.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRec.java
new file mode 100644
index 0000000..8b401b0
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRec.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRel.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRel.java
new file mode 100644
index 0000000..47bf31a
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPubRel.java
@@ -0,0 +1,66 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPuback.java
new file mode 100644
index 0000000..2004d5d
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPuback.java
@@ -0,0 +1,120 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPublish.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPublish.java
new file mode 100644
index 0000000..224bd47
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsPublish.java
@@ -0,0 +1,210 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegack.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegack.java
new file mode 100644
index 0000000..608d578
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegack.java
@@ -0,0 +1,91 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegister.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegister.java
new file mode 100644
index 0000000..1a2ad49
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsRegister.java
@@ -0,0 +1,101 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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

+		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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSearchGW.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSearchGW.java
new file mode 100644
index 0000000..634b6a7
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSearchGW.java
@@ -0,0 +1,67 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSuback.java
new file mode 100644
index 0000000..9fd4264
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSuback.java
@@ -0,0 +1,192 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSubscribe.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSubscribe.java
new file mode 100644
index 0000000..a90e693
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsSubscribe.java
@@ -0,0 +1,212 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+//import org.eclipse.paho.mqttsn.gateway.utils.GatewayLogger;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsuback.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsuback.java
new file mode 100644
index 0000000..c058200
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsuback.java
@@ -0,0 +1,68 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsubscribe.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsubscribe.java
new file mode 100644
index 0000000..0f4f9d3
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsUnsubscribe.java
@@ -0,0 +1,188 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsg.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsg.java
new file mode 100644
index 0000000..8245371
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsg.java
@@ -0,0 +1,75 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgReq.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgReq.java
new file mode 100644
index 0000000..f5d415c
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgReq.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgResp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgResp.java
new file mode 100644
index 0000000..8120b0b
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgResp.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgUpd.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgUpd.java
new file mode 100644
index 0000000..f1975d6
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillMsgUpd.java
@@ -0,0 +1,74 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopic.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopic.java
new file mode 100644
index 0000000..7c6c5f8
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopic.java
@@ -0,0 +1,108 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicReq.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicReq.java
new file mode 100644
index 0000000..471670e
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicReq.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicResp.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicResp.java
new file mode 100644
index 0000000..4df7379
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicResp.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+/**

+ * 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-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicUpd.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicUpd.java
new file mode 100644
index 0000000..3960e58
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/messages/mqtts/MqttsWillTopicUpd.java
@@ -0,0 +1,106 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.messages.mqtts;

+

+import java.io.UnsupportedEncodingException;

+import org.eclipse.paho.mqttsn.gateway.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-Gateway/src/org/eclipse/paho/mqttsn/gateway/timer/TimerService.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/timer/TimerService.java
new file mode 100644
index 0000000..1568569
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/timer/TimerService.java
@@ -0,0 +1,167 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.timer;

+

+import java.util.Timer;

+import java.util.TimerTask;

+import java.util.Vector;

+

+import org.eclipse.paho.mqttsn.gateway.core.Dispatcher;

+import org.eclipse.paho.mqttsn.gateway.messages.Message;

+import org.eclipse.paho.mqttsn.gateway.messages.control.ControlMessage;

+//import org.eclipse.paho.mqttsn.gateway.timer.TimerService.TimeoutTimerTask;

+import org.eclipse.paho.mqttsn.gateway.utils.Address;

+

+

+public class TimerService {

+	

+	private static TimerService instance = null;

+	

+	private Timer timer;

+	private Dispatcher dispatcher;

+	private Vector<TimeoutTimerTask> timeoutTasks;

+

+

+	/**

+	 * Constructor.

+	 */

+	public TimerService() {

+		timer = new Timer();

+		dispatcher = Dispatcher.getInstance();	

+		timeoutTasks = new Vector<TimeoutTimerTask>();

+	}

+	

+	/**

+	 * This method returns the instance of this object.If there no such an instance

+	 * a new object is created.

+	 * 

+	 * @return The instance of this object.

+	 */

+	public static synchronized TimerService getInstance() {

+		if (instance == null) {

+			instance = new TimerService();

+		}

+		return instance;

+	}

+

+	/**

+	 * This method schedules a TimeoutTimerTask to the timer for future executions and

+	 * stores it to a list. 

+	 * 

+	 * @see TimeoutTimerTask

+	 * 

+	 * @param clientAddress The address of the client.

+	 * @param type The type of task/timeout (WAITING_WILLTOPIC, WAITING_WILLMESSAGE, KEEP_ALIVE,etc.).

+	 * @param timeout Expresses the delay and the period (in seconds) of executing the TimeoutTimerTask.

+	 */

+	public void register(Address address, int type, int timeout) {

+		long delay = timeout * 1000;

+		long period = timeout * 1000;

+		

+		TimeoutTimerTask timeoutTimerTask = new TimeoutTimerTask(address,type);

+

+		//put this timeoutTimerTask in a list

+		timeoutTasks.add(timeoutTimerTask);

+		

+		//schedule for future executions

+		timer.scheduleAtFixedRate(timeoutTimerTask, delay, period);		

+	}

+

+	/**

+	 * This method removes a TimeoutTimerTask from the list and cancels it. 

+	 * 

+	 * @see TimeoutTimerTask

+	 * 

+	 * @param clientAddress The address of the client.

+	 * @param type The type of task/timeout (WAITING_WILLTOPIC, WAITING_WILLMESSAGE, etc.).

+	 */

+	public void unregister(Address address, int type) {

+		for(int i = 0 ; i<timeoutTasks.size(); i++) {

+			TimeoutTimerTask timeout = (TimeoutTimerTask)timeoutTasks.get(i);

+			if(timeout.getAddress().equal(address)) 

+				if (timeout.getType() == type){

+					timeoutTasks.remove(i);

+					timeout.cancel();

+					break;

+				}

+		}

+	}

+	

+	/**

+	 * This method removes a TimeoutTimerTask from the list and cancels it. 

+	 * 

+	 * @see TimeoutTimerTask

+	 * 

+	 * @param clientAddress The address of the client.

+	 */

+	public void unregister(Address address){

+		for(int i = timeoutTasks.size()-1; i >= 0; i--) {

+			TimeoutTimerTask timeout = (TimeoutTimerTask)timeoutTasks.get(i);

+			if(timeout.getAddress().equal(address)){

+					timeoutTasks.remove(i);

+					timeout.cancel();

+			}

+		}		

+	}

+	

+

+	/**

+	 * This object represents a TimeoutTimerTask.It is uniquely identified

+	 * by the clientAddress and the type of task/timeout (WAITING_WILLTOPIC, etc.)

+	 *

+	 */

+	 public class TimeoutTimerTask extends TimerTask {

+		Address address;

+		int type;

+		

+		/**

+		* Constructor.

+		* 

+		* @param clientAddress The address of the client.

+		* @param type The type of task/timeout (WAITING_WILLTOPIC, WAITING_WILLMESSAGE,etc.

+		*/

+		public TimeoutTimerTask(Address addr, int type) {

+			this.address = addr;

+			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(this.address);

+			msg.setType(Message.CONTROL_MSG);

+			msg.setControlMessage(controlMsg);

+			

+			//put this message to the Dispatcher's queue

+			dispatcher.putMessage(msg);

+        }

+

+		public Address getAddress() {

+			return address;

+		}

+

+		public int getType() {

+			return type;

+		}

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Address.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Address.java
new file mode 100644
index 0000000..10796c2
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Address.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2014 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.gateway.utils;
+
+import java.net.InetAddress;
+
+public abstract class Address {
+	
+	public abstract boolean equal(Object o);
+
+	public abstract void setIPaddress(Address addr);
+	
+	public abstract byte[] getAddress() ;
+	
+	public abstract InetAddress getIPaddress() ;
+	
+	public abstract int getPort();	
+}
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ClientAddress.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ClientAddress.java
new file mode 100644
index 0000000..4a3ddf7
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ClientAddress.java
@@ -0,0 +1,103 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.utils;

+

+import java.net.InetAddress;

+

+

+/**

+* This class represents the address of a client.It includes also the IP address and the 

+* port of the forwarder with which this client is connected.

+* 

+* Parts of this code were imported from com.ibm.zurich.mqttz_gw.util.SAaddress.java

+* 

+*/

+public class ClientAddress extends Address{

+	

+	private byte[] clientAddress = null;

+	private InetAddress ipAddress = null;

+	private int port = 0;

+	private boolean isEncaps;  //whether fw-encapsulation is used by this client or not

+	private byte[] encaps;

+

+	

+	public ClientAddress(byte[] addr) {

+		this.clientAddress = addr;

+		this.ipAddress = null;

+		this.port = 0;

+		this.isEncaps = true;

+	}

+	

+	public ClientAddress(byte[] addr, InetAddress ipAddr, int port, boolean isencaps, byte[] encaps) {

+		this.clientAddress = addr;

+		this.ipAddress = ipAddr;

+		this.port   = port;

+		this.isEncaps = isencaps;

+		this.encaps = encaps;

+	}

+	

+	public boolean isEncaps() {

+		return isEncaps;

+	}

+	public byte[] getEncaps() {

+		return encaps;

+	}

+	

+	public byte[] getAddress() {

+		return this.clientAddress;

+	}

+	

+	public InetAddress getIPaddress() {

+		return this.ipAddress;

+	}

+	

+	public int getPort() {

+		return this.port;

+	}

+		

+	public void setIPaddress(Address addr) {

+		ClientAddress clientAddr = (ClientAddress) addr;

+		this.ipAddress = clientAddr.ipAddress;

+		this.port   = clientAddr.port;

+	}

+

+	public boolean equal(Object o) {

+		if(o == null) return false;

+		if(!(o instanceof ClientAddress)) return false;

+		if(o == this) return true;

+		

+		ClientAddress ca = (ClientAddress)o;

+		if(clientAddress == null) {

+			if(ca.clientAddress == null) {

+				return true;

+			} else {

+				return false;

+			}

+		} else {

+			if(ca.clientAddress == null || clientAddress.length != ca.clientAddress.length) 

+				return false;

+			boolean ok = true;

+			for(int i = 0; i < clientAddress.length; i++) {

+				if(clientAddress[i] != ca.clientAddress[i]) {

+					ok = false;

+					break;

+				}

+			}

+			return ok;

+		}

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ConfigurationParser.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ConfigurationParser.java
new file mode 100644
index 0000000..18bc0ff
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/ConfigurationParser.java
@@ -0,0 +1,357 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.utils;

+

+import java.io.File;

+import java.io.FileInputStream;

+import java.io.FileNotFoundException;

+import java.io.IOException;

+import java.util.Hashtable;

+import java.util.Iterator;

+import java.util.Properties;

+

+import org.eclipse.paho.mqttsn.gateway.exceptions.MqttsException;

+

+public class ConfigurationParser {

+	

+	public ConfigurationParser() {}

+

+	public static void parseFile(String filename) throws MqttsException {

+		File param = new File(filename);

+		

+		FileInputStream stream;

+		try {

+			stream = new FileInputStream(param);

+			

+			Properties pr = new Properties();

+			pr.load(stream);

+			

+			

+			//load from configuration file the data related to the gateway

+			

+			int logLevel;

+			String level = pr.getProperty("logLevel");

+			if (level == null)

+				throw new MqttsException("There is no log level defined");

+			if(level.equalsIgnoreCase("INFO"))

+				logLevel = GatewayLogger.INFO;

+			else if(level.equalsIgnoreCase("WARN"))

+				logLevel = GatewayLogger.WARN;

+			else if(level.equalsIgnoreCase("ERROR"))

+				logLevel = GatewayLogger.ERROR;

+			else

+				logLevel = GatewayLogger.INFO;

+			

+			GatewayLogger.setLogLevel(logLevel);

+				

+			String logDir = pr.getProperty("logDir");

+			if (logDir == null)

+				logDir = "log";

+			

+			boolean exists = new File (logDir).exists();

+			if (!exists){

+				boolean ok = (new File(logDir)).mkdir();

+		    	if (!ok) 

+		    		throw new MqttsException("Cannot create log directory.");

+			}

+			

+			String logFile = pr.getProperty("logFile");

+			if (logFile == null)

+				logFile = "mqtts_gateway.log";

+			GatewayLogger.setLogFile(logDir+"/"+logFile);

+							

+			String spr = pr.getProperty("predfTopicIdSize");

+			if(spr == null)

+				throw new MqttsException("There is no predefined topic id size defined");

+			int predfTopicIdSize = 0;

+			try{

+				predfTopicIdSize = Integer.parseInt(spr);

+				if(predfTopicIdSize < 1)

+					throw new MqttsException("Predefined topic id size should be greater than 1");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Predefined topic id size - Format error "+ e.getMessage());

+			}				

+			GWParameters.setPredfTopicIdSize(predfTopicIdSize);

+			

+			//load the predefined topic ids

+			String predefinedTopicsFile = pr.getProperty("predefinedTopicsFile");

+			File predef;

+			if (predefinedTopicsFile == null)

+				throw new MqttsException("There is no predefined topic ids file defined");

+			predef = new File(predefinedTopicsFile);

+			FileInputStream predefStream = new FileInputStream(predef);

+			Properties pr1 = new Properties();

+			

+			pr1.load(predefStream);

+			

+			Iterator<?> iter = pr1.keySet().iterator();

+			Iterator<?> iterVal = pr1.values().iterator();

+			Hashtable<Integer, String> table = new Hashtable<Integer, String>(); 

+			while (iter.hasNext()) {

+				try{

+					Integer topicId = new Integer((String)iter.next());	

+					String topicName = (String)iterVal.next();

+					if(topicId.intValue() > 0 && topicId.intValue() <= GWParameters.getPredfTopicIdSize() && !table.containsValue(topicName)){

+						table.put(topicId, topicName);

+					}

+				}catch(NumberFormatException e){

+					//do nothing just omit this entry				

+				}					

+			}			

+			GWParameters.setPredefTopicIdTable(table);

+			

+			

+			String sGwId = pr.getProperty("gwId");

+			if (sGwId == null)

+				throw new MqttsException("There is no gateway id defined");			

+			int gwId = 0;

+			try{

+				gwId = Integer.parseInt(sGwId);

+			}catch(NumberFormatException e){

+				throw new MqttsException("Gateway Id - Format error "+ e.getMessage());				

+			}

+			GWParameters.setGwId(gwId);

+	

+			

+			String sadvper = pr.getProperty("advPeriod");

+			if (sadvper == null)

+				throw new MqttsException("There is no advertising period defined");			

+			long advPeriod = 0;

+			try{

+				advPeriod = Integer.parseInt(sadvper);

+				if(advPeriod <=0)

+					throw new MqttsException("Advertising period should be greater than 0 seconds");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Advertising period - Format error "+ e.getMessage());				

+			}

+			GWParameters.setAdvPeriod(advPeriod);

+

+			

+			String skeepalive = pr.getProperty("keepAlivePeriod");

+			if (skeepalive == null)

+				throw new MqttsException("There is no keep alive period defined");			

+			int keepAlivePeriod = 0;

+			try{

+				keepAlivePeriod = Integer.parseInt(skeepalive);

+				if (keepAlivePeriod <=0)

+					throw new MqttsException("Keep alive period should be greater than 0 seconds");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Keep alive period - Format error "+ e.getMessage());				

+			}			

+			GWParameters.setKeepAlivePeriod(keepAlivePeriod);

+

+			

+			String smret = pr.getProperty("maxRetries");

+			if (smret == null)

+				throw new MqttsException("There is no maximum retries defined");			

+			int maxRetries = 0;

+			try{

+				maxRetries = Integer.parseInt(smret);

+				if(maxRetries < 0)

+					throw new MqttsException("Maximum retries cannot be negative");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Maximum retries - Format error "+ e.getMessage());				

+			}

+			GWParameters.setMaxRetries(maxRetries);

+			

+			

+			String swait = pr.getProperty("waitingTime");

+			if (swait == null)

+				throw new MqttsException("There is no waiting time defined");			

+			int waitingTime = 0;

+			try{

+				waitingTime = Integer.parseInt(swait);

+				if(waitingTime <= 0)

+					throw new MqttsException("Waiting time should be greater than 0 seconds");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Waiting time - Format error "+ e.getMessage());				

+			}

+			GWParameters.setWaitingTime(waitingTime);

+			

+			

+			String smaxlength = pr.getProperty("maxMqttsLength");

+			if (smaxlength == null)

+				throw new MqttsException("There is no maximum Mqtts length defined");			

+			int maxMqttsLength = 0;

+			try{

+				maxMqttsLength = Integer.parseInt(smaxlength);

+				if(maxMqttsLength < 2)

+					throw new MqttsException("Maximum Mqtts length should be greater than 1");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Maximum Mqtts length - Format error "+ e.getMessage());				

+			}

+			GWParameters.setMaxMqttsLength(maxMqttsLength);

+

+			

+			String sminlength = pr.getProperty("minMqttsLength");

+			if (sminlength == null)

+				throw new MqttsException("There is no maximum Mqtts length defined");			

+			int minMqttsLength = 0;

+			try{

+				minMqttsLength = Integer.parseInt(sminlength);

+				if(minMqttsLength < 2)

+					throw new MqttsException("Minimum Mqtts length should be greater than 1");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Mimimum Mqtts length - Format error "+ e.getMessage());				

+			}

+			GWParameters.setMinMqttsLength(minMqttsLength);

+

+			

+			String sudp = pr.getProperty("udpPort");

+			if (sudp == null)

+				throw new MqttsException("There is no UDP port defined");			

+			int udpPort = 0;

+			try{

+				udpPort = Integer.parseInt(sudp);

+				if(udpPort < 1024 || udpPort > 65535)

+					throw new MqttsException("UDP port number out of range");

+			}catch(NumberFormatException e){

+				throw new MqttsException("UDP port number - Format error "+ e.getMessage());				

+			}

+			GWParameters.setUdpPort(udpPort);

+			

+			

+			String brokerURL = pr.getProperty("brokerURL");

+			if (brokerURL == null)

+				throw new MqttsException("There is no broker URL defined");		

+			GWParameters.setBrokerURL(brokerURL);

+					

+			

+			String stcp = pr.getProperty("brokerTcpPort");

+			if (stcp == null)

+				throw new MqttsException("There is no broker TCP port defined");			

+			int brokerTcpPort = 0;

+			try{

+				brokerTcpPort = Integer.parseInt(stcp);

+				if(brokerTcpPort < 1024 || brokerTcpPort > 65535)

+					throw new MqttsException("TCP port number out of range");

+			}catch(NumberFormatException e){

+				throw new MqttsException("TCP port number - Format error "+ e.getMessage());				

+			}

+			GWParameters.setBrokerTcpPort(brokerTcpPort);

+			

+			

+			String shandtim = pr.getProperty("handlerTimeout");

+			if (shandtim == null)

+				throw new MqttsException("There is no handler timeout defined");			

+			long handlerTimeout = 0;

+			try{

+				handlerTimeout = Long.parseLong(shandtim);

+				if(handlerTimeout <=0)

+					throw new MqttsException("Handler timeout should be greater than 0");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Handler timeout - Format error "+ e.getMessage());				

+			}

+			GWParameters.setHandlerTimeout(handlerTimeout);

+			

+			

+			String sfortim = pr.getProperty("forwarderTimeout");

+			if (sfortim == null)

+				throw new MqttsException("There is no forwarder timeout defined");			

+			long forwarderTimeout = 0;

+			try{

+				forwarderTimeout = Long.parseLong(sfortim);

+				if(forwarderTimeout <=0)

+					throw new MqttsException("Forwarder timeout should be greater than 0");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Forwarder timeout - Format error "+ e.getMessage());				

+			}

+			GWParameters.setForwarderTimeout(forwarderTimeout);

+			

+			

+			String scheckper = pr.getProperty("checkingPeriod");

+			if (scheckper == null)

+				throw new MqttsException("There is no checking period defined");			

+			long checkingPeriod = 0;

+			try{

+				checkingPeriod = Long.parseLong(scheckper);

+				if(checkingPeriod <=0)

+					throw new MqttsException("Checking period should be greater than 0");

+			}catch(NumberFormatException e){

+				throw new MqttsException("Checking period - Format error "+ e.getMessage());				

+			}

+			GWParameters.setCkeckingPeriod(checkingPeriod);

+			

+			

+			String serialUrl = pr.getProperty("serialPortURL");

+			if (serialUrl == null)

+				throw new MqttsException("There is no serial port url defined");		

+			GWParameters.setSerialPortURL(serialUrl);

+

+			

+			String clientIntString = pr.getProperty("clientInterfaces");

+			if (clientIntString == null)

+				throw new MqttsException("There are no client interfaces defined");		

+			GWParameters.setClientIntString(clientIntString);

+			

+			

+			String protocolName = pr.getProperty("protocolName");

+			GWParameters.setProtocolName(protocolName);

+			

+			

+			int protocolVersion = Integer.parseInt(pr.getProperty("protocolVersion"));

+			GWParameters.setProtocolVersion(protocolVersion);

+			

+			

+			boolean retain = false;

+			String retainString = pr.getProperty("retain");

+			if (retainString != null) {

+				if (retainString.trim().equalsIgnoreCase("true")) {

+					retain = true;

+				}

+			}

+			GWParameters.setRetain(retain);

+			

+			

+			int willQoS = Integer.parseInt(pr.getProperty("willQoS"));

+			GWParameters.setWillQoS(willQoS);

+

+			

+			boolean willFlag = false;

+			String willFlagString = pr.getProperty("willFlag");

+			if (willFlagString != null) {

+				if (willFlagString.trim().equalsIgnoreCase("true")) {

+					willFlag = true;

+				}

+			}

+			GWParameters.setWillFlag(willFlag);

+			//System.out.println(">> willFlag= " + GWParameters.isWillFlag());

+			

+			

+			boolean cleanSession = false;

+			String cleanSessionString = pr.getProperty("cleanSession");

+			if (cleanSessionString != null) {

+				if (cleanSessionString.trim().equalsIgnoreCase("true")) {

+					cleanSession = true;

+				}

+			}

+			GWParameters.setCleanSession(cleanSession);

+			

+			

+			String willTopic = pr.getProperty("willTopic"); 

+			GWParameters.setWillTopic(willTopic);

+			

+			String willMessage = pr.getProperty("willMessage");

+			GWParameters.setWillMessage(willMessage);

+			

+		}catch (FileNotFoundException e) {

+			throw new MqttsException (e.getMessage());

+		} catch (IOException e) {

+			throw new MqttsException (e.getMessage());

+		}			

+	}	

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GWParameters.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GWParameters.java
new file mode 100644
index 0000000..006d3d6
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GWParameters.java
@@ -0,0 +1,337 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.utils;

+

+import java.net.InetAddress;

+import java.util.Hashtable;

+import java.util.Vector;

+

+import org.eclipse.paho.mqttsn.gateway.client.ClientInterface;

+

+public class GWParameters {

+	

+	//the ID of the gateway (from 0 up to 255)

+	private static int gwId;

+	

+	//the address of the gateway

+	private static GatewayAddress gatewayAddress; 

+	

+	//the period (in seconds) of broadcasting the Mqtts ADVERTISE message to the network

+	public static long advPeriod; 

+

+	//the period (in seconds) of sending the Mqtt PINGRESP message to the broker

+	public static int keepAlivePeriod; 

+

+	//maximum retries of sending a message to the client

+	public static int maxRetries;

+	

+	//maximum time (in seconds) waiting for a message from the client

+	public static int waitingTime;

+	

+	//the maximum number of predefined topic ids

+	private static int predfTopicIdSize;

+	

+	//the maximum length of the Mqtts message

+	private static int maxMqttsLength;

+

+	//the minimum length of the Mqtts message

+	private static int minMqttsLength;

+	

+	//the IP address of the gateway

+	private static InetAddress ipAddress;

+	

+	//the URL of the gateway

+	private static String gatewayURL;

+	

+	//the UDP port that will be used for the UDP socket of the ClientIPInterface

+	private static int udpPort;

+	

+	//the URL of the broker

+	private static String brokerURL;

+	

+	//the TCP port where broker listens

+	private static int brokerTcpPort;

+	

+	//serial port parameters

+	private static String serialPortURL;

+	

+	//the time (in seconds) that a ClientMsgHandler can remain inactive

+	private static long handlerTimeout;

+	

+	//the time (in seconds) that a Forwarder can remain inactive (we don't have any message)

+	private static long forwarderTimeout;

+	

+	//the period (in seconds) that a control message is sent to all ClientMsgHandlers for removing 

+	//themselves from Dispatcher's mapping table if they are inactive for at least handlerTimeout seconds

+	private static long ckeckingPeriod;

+	

+	//a String for storing the names of all available client interfaces

+	private static String clientIntString;

+	

+	//a vector for storing all available client interfaces

+	private static Vector<ClientInterface> clientInterfacesVector;

+	

+	//a hashtable for storing predefined topic ids

+	private static Hashtable<?, ?> predefTopicIdTable;

+

+	

+	//other parameters of the Mqtt CONNECT message that GatewayMsgHandler sends to the broker

+	private static String protocolName;

+	private static int protocolVersion;

+	private static boolean retain;

+	private static int willQoS;

+	private static boolean willFlag;	

+	private static boolean cleanSession;

+	private static String willTopic; 

+	private static String willMessage;

+		

+	/**

+	 * 

+	 */	

+	

+	public static int getGwId() {

+		return gwId;

+	}

+

+	public static void setGwId(int gwId) {

+		GWParameters.gwId = gwId;

+	}

+

+	public static long getAdvPeriod() {

+		return advPeriod;

+	}

+

+	public static void setAdvPeriod(long advPeriod) {

+		GWParameters.advPeriod = advPeriod;

+	}

+

+	public static int getMaxRetries() {

+		return maxRetries;

+	}

+

+	public static void setMaxRetries(int maxRetries) {

+		GWParameters.maxRetries = maxRetries;

+	}

+

+	public static int getWaitingTime() {

+		return waitingTime;

+	}

+

+	public static void setWaitingTime(int waitingTime) {

+		GWParameters.waitingTime = waitingTime;

+	}

+

+	public static int getPredfTopicIdSize() {

+		return predfTopicIdSize;

+	}

+

+	public static void setPredfTopicIdSize(int predfTopicIdSize) {

+		GWParameters.predfTopicIdSize = predfTopicIdSize;

+	}

+

+	public static int getUdpPort() {

+		return udpPort;

+	}

+

+	public static void setUdpPort(int udpPort) {

+		GWParameters.udpPort = udpPort;

+	}

+

+	public static String getBrokerURL() {

+		return brokerURL;

+	}

+

+	public static void setBrokerURL(String brokerURL) {

+		GWParameters.brokerURL = brokerURL;

+	}

+

+	public static int getBrokerTcpPort() {

+		return brokerTcpPort;

+	}

+

+	public static void setBrokerTcpPort(int brokerTcpPort) {

+		GWParameters.brokerTcpPort = brokerTcpPort;

+	}

+

+	public static long getHandlerTimeout() {

+		return handlerTimeout;

+	}

+

+	public static void setHandlerTimeout(long handlerTimeout) {

+		GWParameters.handlerTimeout = handlerTimeout;

+	}

+

+	public static int getKeepAlivePeriod() {

+		return keepAlivePeriod;

+	}

+

+	public static void setKeepAlivePeriod(int keepAlivePeriod) {

+		GWParameters.keepAlivePeriod = keepAlivePeriod;

+	}

+

+	public static long getCkeckingPeriod() {

+		return ckeckingPeriod;

+	}

+

+	public static void setCkeckingPeriod(long ckeckingPeriod) {

+		GWParameters.ckeckingPeriod = ckeckingPeriod;

+	}

+

+	public static GatewayAddress getGatewayAddress() {

+		return gatewayAddress;

+	}

+

+	public static void setGatewayAddress(GatewayAddress gatewayAddress) {

+		GWParameters.gatewayAddress = gatewayAddress;

+	}

+

+	public static InetAddress getIpAddress() {

+		return ipAddress;

+	}

+

+	public static void setIpAddress(InetAddress ipAddr) {

+		ipAddress = ipAddr;

+	}

+

+	public static String getGatewayURL() {

+		return gatewayURL;

+	}

+

+	public static void setGatewayURL(String gatewayURL) {

+		GWParameters.gatewayURL = gatewayURL;

+	}

+	

+	public static String getClientIntString() {

+		return clientIntString;

+	}

+

+	public static void setClientIntString(String clientIntString) {

+		GWParameters.clientIntString = clientIntString;

+	}

+	

+	public static Vector<ClientInterface> getClientInterfaces() {

+		return clientInterfacesVector;

+	}

+

+	public static void setClientInterfacesVector(Vector<ClientInterface> clientInterfacesVector) {

+		GWParameters.clientInterfacesVector = clientInterfacesVector;

+	}

+

+	public static String getProtocolName() {

+		return protocolName;

+	}

+

+	public static void setProtocolName(String protocolName) {

+		GWParameters.protocolName = protocolName;

+	}

+

+	public static int getProtocolVersion() {

+		return protocolVersion;

+	}

+

+	public static void setProtocolVersion(int protocolVersion) {

+		GWParameters.protocolVersion = protocolVersion;

+	}

+

+	public static boolean isRetain() {

+		return retain;

+	}

+

+	public static void setRetain(boolean retain) {

+		GWParameters.retain = retain;

+	}

+

+	public static int getWillQoS() {

+		return willQoS;

+	}

+

+	public static void setWillQoS(int willQoS) {

+		GWParameters.willQoS = willQoS;

+	}

+

+	public static boolean isWillFlag() {

+		return willFlag;

+	}

+

+	public static void setWillFlag(boolean willFlag) {

+		GWParameters.willFlag = willFlag;

+	}

+

+	public static boolean isCleanSession() {

+		return cleanSession;

+	}

+

+	public static void setCleanSession(boolean cleanSession) {

+		GWParameters.cleanSession = cleanSession;

+	}

+

+	public static String getWillTopic() {

+		return willTopic;

+	}

+

+	public static void setWillTopic(String willTopic) {

+		GWParameters.willTopic = willTopic;

+	}

+

+	public static String getWillMessage() {

+		return willMessage;

+	}

+

+	public static void setWillMessage(String willMessage) {

+		GWParameters.willMessage = willMessage;

+	}

+

+	public static long getForwarderTimeout() {

+		return forwarderTimeout;

+	}

+

+	public static void setForwarderTimeout(long forwarderTimeout) {

+		GWParameters.forwarderTimeout = forwarderTimeout;

+	}

+

+	public static int getMaxMqttsLength() {

+		return maxMqttsLength;

+	}

+

+	public static void setMaxMqttsLength(int maxMqttsLength) {

+		GWParameters.maxMqttsLength = maxMqttsLength;

+	}

+

+	public static int getMinMqttsLength() {

+		return minMqttsLength;

+	}

+

+	public static void setMinMqttsLength(int minMqttsLength) {

+		GWParameters.minMqttsLength = minMqttsLength;

+	}

+

+	public static Hashtable<?, ?> getPredefTopicIdTable() {

+		return predefTopicIdTable;

+	}

+

+	public static void setPredefTopicIdTable(Hashtable<?, ?> predefTopicIdTable) {

+		GWParameters.predefTopicIdTable = predefTopicIdTable;

+	}

+

+	public static String getSerialPortURL() {

+		return serialPortURL;

+	}

+

+	public static void setSerialPortURL(String serialPortURL) {

+		GWParameters.serialPortURL = serialPortURL;

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayAddress.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayAddress.java
new file mode 100644
index 0000000..be3efc6
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayAddress.java
@@ -0,0 +1,93 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.utils;

+

+import java.net.InetAddress;

+

+

+/**

+* This class represents the address of the gateway.It includes also the IP address of the

+* gateway.

+* 

+* Parts of this code were imported from com.ibm.zurich.mqttz_gw.util.SAaddress.java

+* 

+*/

+public class GatewayAddress extends Address{

+	

+	private byte[] gatewayAddress = null;

+	private InetAddress ipAddress = null;

+	private int port = 0;

+

+	

+	public GatewayAddress(byte[] addr) {

+		this.gatewayAddress = addr;

+		this.ipAddress = null;

+		this.port = 0;

+	}

+	

+	public GatewayAddress(byte[] addr, InetAddress ipAddr, int port) {

+		this.gatewayAddress = addr;

+		this.ipAddress = ipAddr;

+		this.port   = port;		

+	}

+	

+	public byte[] getAddress() {

+		return this.gatewayAddress;

+	}

+	

+	public InetAddress getIPaddress() {

+		return this.ipAddress;

+	}

+	

+	public int getPort() {

+		return this.port;

+	}

+	

+	public void setIPaddress(Address addr) {

+		GatewayAddress gatewayAddr = (GatewayAddress) addr;

+		this.ipAddress = gatewayAddr.ipAddress;

+		this.port   = gatewayAddr.port;

+	}

+

+	public boolean equal(Object o) {

+		if(o == null) return false;

+		if(!(o instanceof GatewayAddress)) return false;

+		if(o == this) return true;

+		

+		GatewayAddress ga = (GatewayAddress)o;

+		if(gatewayAddress == null) {

+			if(ga.gatewayAddress == null) {

+				return true;

+			} else {

+				return false;

+			}

+		} else {

+			if(ga.gatewayAddress == null || gatewayAddress.length != ga.gatewayAddress.length) 

+				return false;

+			boolean ok = true;

+			for(int i = 0; i < gatewayAddress.length; i++) {

+				if(gatewayAddress[i] != ga.gatewayAddress[i]) {

+					ok = false;

+					break;

+				}

+			}

+			if(!(ipAddress.equals(ga.getIPaddress()) && port == ga.getPort()))

+				ok = false;

+			return ok;

+		}

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayLogger.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayLogger.java
new file mode 100644
index 0000000..d5a076c
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/GatewayLogger.java
@@ -0,0 +1,105 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.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.gateway.exceptions.MqttsException;

+

+public class GatewayLogger {

+	

+	public final static int INFO  = 1;

+	public final static int WARN  = 2;

+	public final static int ERROR = 3;

+	

+	private static int LOG_LEVEL = INFO;

+	

+

+	public static void info(String msg) {

+		DateFormat dFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");

+		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 MMM yyyy HH:mm:ss z");

+		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 MMM yyyy HH:mm:ss z");

+		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:

+					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();

+			printWriter.println(dFormat.format(new Date())+ "  INFO:  -----------------------------------------Mqtts Gateway starting----------------------------------------");

+			printWriter.println(dFormat.format(new Date())+ "  INFO:  Loading Mqtts Gateway parameters....");

+		} catch(IOException e) {

+			e.printStackTrace();

+			throw new MqttsException (e.getMessage());

+		}

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/MsgQueue.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/MsgQueue.java
new file mode 100644
index 0000000..8492e06
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/MsgQueue.java
@@ -0,0 +1,59 @@
+/*******************************************************************************

+ * Copyright (c) 2008, 2014 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.gateway.utils;

+

+import java.util.LinkedList;

+

+public class MsgQueue {	

+	

+	private LinkedList<Object> queue = new LinkedList<Object>();

+	

+	 /**

+	 * @param o

+	 */

+	public void addLast(Object o) {

+		synchronized(queue){

+			  queue.add(o);

+			  queue.notify();

+		  }

+	  }

+	  

+	 /**

+	 * @param o

+	 */

+	public void addFirst(Object o) {

+		synchronized(queue){

+			  queue.addFirst(o);

+		      queue.notify();

+		    }

+	  }

+	

+	public Object get() throws InterruptedException {

+		synchronized(queue){

+			while (queue.isEmpty())

+				queue.wait();

+			return queue.removeFirst();

+	    }

+	}

+	  

+	  /**

+	 * @return

+	 */

+	public int size(){

+		return queue.size();

+	}

+}
\ No newline at end of file
diff --git a/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Utils.java b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Utils.java
new file mode 100644
index 0000000..2c6beeb
--- /dev/null
+++ b/apps/MQTTSN-Gateway/src/org/eclipse/paho/mqttsn/gateway/utils/Utils.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2014 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.gateway.utils;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * 
+ * This class provides various utility methods.
+ * 
+ * Parts of this code were imported from com.ibm.mqttclient.ia92.MqttUtils.java
+ *
+ */
+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) {
+			GatewayLogger.log(GatewayLogger.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) {
+				GatewayLogger.log(GatewayLogger.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;
+	}
+
+	
+	/**
+	 * @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