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