/**
*****************************************************************************
Copyright (c) 2016 IBM Corporation and other Contributors.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Sathiskumar Palaniappan - Initial Contribution
*****************************************************************************
*
*/
package com.ibm.iotf.client.gateway;
import java.io.IOException;
import java.util.Properties;
import junit.framework.TestCase;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.junit.Test;
import com.google.gson.JsonObject;
import com.ibm.iotf.client.IoTFCReSTException;
import com.ibm.iotf.client.api.APIClient;
import com.ibm.iotf.client.app.ApplicationClient;
/**
* This test verifies that the device receives the command published by the application
* successfully.
*
*/
public class GatewayCommandSubscriptionTest extends TestCase{
private final static String GATEWAY_PROPERTIES_FILE = "/gateway.properties";
private final static String APPLICATION_PROPERTIES_FILE = "/application.properties";
private final static String DEVICE_TYPE = "iotsampleType";
private final static String SIMULATOR_DEVICE_ID = "Arduino02";
private static String GATEWAY_DEVICE_TYPE = "";
private static String GATEWAY_DEVICE_ID = "";
private static GatewayClient gwClient = null;
private static APIClient apiClient = null;
public void setUp() {
// do the setup
createGatewayClient(GATEWAY_PROPERTIES_FILE);
try {
if(apiClient != null) {
addDeviceType(DEVICE_TYPE);
addDevice(DEVICE_TYPE, SIMULATOR_DEVICE_ID);
}
} catch (IoTFCReSTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tearDown() throws IoTFCReSTException {
gwClient.disconnect();
if(apiClient != null) {
apiClient.deleteDevice(DEVICE_TYPE, SIMULATOR_DEVICE_ID);
apiClient.deleteDeviceType(DEVICE_TYPE);
}
}
/**
* This sample adds a device type using the Java Client Library.
* @throws IoTFCReSTException
*/
private void addDeviceType(String deviceType) throws IoTFCReSTException {
try {
System.out.println("<-- Checking if device type "+deviceType +" already created in Watson IoT Platform");
boolean exist = apiClient.isDeviceTypeExist(deviceType);
if (!exist) {
System.out.println("<-- Adding device type "+deviceType + " now..");
// device type to be created in WIoTP
apiClient.addDeviceType(deviceType, deviceType, null, null);
}
} catch(IoTFCReSTException e) {
System.err.println("ERROR: unable to add manually device type " + e.getMessage());
e.printStackTrace();
}
}
/**
* Add a device under the given gateway using the Java Client Library.
* @throws IoTFCReSTException
*/
private void addDevice(String deviceType, String deviceId) throws IoTFCReSTException {
try {
System.out.println("<-- Checking if device " + deviceId +" with deviceType " +
deviceType +" exists in Watson IoT Platform");
boolean exist = this.gwClient.api().isDeviceExist(deviceType, deviceId);
if(!exist) {
System.out.println("<-- Creating device " + deviceId +" with deviceType " +
deviceType +" now..");
gwClient.api().registerDeviceUnderGateway(deviceType, deviceId,
this.gwClient.getGWDeviceType(),
this.gwClient.getGWDeviceId());
}
} catch (IoTFCReSTException ex) {
System.out.println("ERROR: unable to add manually device " + deviceId);
}
}
/**
* This method creates a GatewayClient instance by passing the required properties
* and connects the Gateway to the Watson IoT Platform by calling the connect function.
*
* After the successful connection to the Watson IoT Platform, the Gateway can perform the following operations,
* 1. Publish events for itself and on behalf of devices connected behind the Gateway
* 2. Subscribe to commands for itself and on behalf of devices behind the Gateway
*/
private static void createGatewayClient(String fileName) {
/**
* Load device properties
*/
Properties props = new Properties();
try {
props.load(GatewayEventPublishTest.class.getResourceAsStream(fileName));
} catch (IOException e1) {
System.err.println("Not able to read the properties file, exiting..");
System.exit(-1);
}
try {
//Instantiate & connect the Gateway by passing the properties file
gwClient = new GatewayClient(props);
gwClient.connect(true);
/**
* Get the Device Type and Device Id to which the application will publish the command
*/
GATEWAY_DEVICE_TYPE = trimedValue(props.getProperty("Gateway-Type"));
GATEWAY_DEVICE_ID = trimedValue(props.getProperty("Gateway-ID"));
/**
* We need APIClient to register the devicetype in Watson IoT Platform
*/
Properties options = new Properties();
options.put("Organization-ID", props.getProperty("Organization-ID"));
options.put("id", "app" + (Math.random() * 10000));
options.put("Authentication-Method","apikey");
options.put("API-Key", props.getProperty("API-Key"));
options.put("Authentication-Token", props.getProperty("API-Token"));
apiClient = new APIClient(options);
} catch (Exception e) {
// Looks like the gateway.property file is not updated with registration details
return;
}
}
@Test
public void testGatewayCommandReception() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
// Ask application to publish the command to this gateway now
publishCommand(true, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void testDeviceCommandReception() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID);
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void test02DeviceCommandReception() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void test03DeviceCommandReception() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json", 2);
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void testNotification() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToGatewayNotification();
}
@Test
public void testDeviceSpecificCommandReception() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "start");
// Ask application to publish the command to this gateway now
publishCommand(false, "start");
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void testDeviceSpecificCommandReceptionWithQoS() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "start", 2);
// Ask application to publish the command to this gateway now
publishCommand(false, "start");
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void testDeviceSpecificCommandReceptionWithFormat() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "start", "json", 2);
// Ask application to publish the command to this gateway now
publishCommand(false, "start");
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertTrue("The command is not received by gateway", callback.commandReceived);
}
@Test
public void testDeviceCommandUnsubscription() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID);
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
count = 0;
callback.clear();
gwClient.unsubscribeFromDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID);
publishCommand(false, null);
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertFalse("The command should not be received by gateway", callback.commandReceived);
}
@Test
public void test02DeviceCommandUnsubscription() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
count = 0;
callback.clear();
gwClient.unsubscribeFromDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertFalse("The command should not be received by gateway", callback.commandReceived);
}
@Test
public void test03DeviceCommandUnsubscription() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
count = 0;
callback.clear();
gwClient.unsubscribeFromDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertFalse("The command should not be received by gateway", callback.commandReceived);
}
@Test
public void test04DeviceCommandUnsubscription() throws MqttException{
//Pass the above implemented CommandCallback as an argument to this device client
GatewayCommandCallback callback = new GatewayCommandCallback();
gwClient.setGatewayCallback(callback);
gwClient.subscribeToDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json", 2);
// Ask application to publish the command to this gateway now
publishCommand(false, null);
int count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
count = 0;
callback.clear();
gwClient.unsubscribeFromDeviceCommands(DEVICE_TYPE, SIMULATOR_DEVICE_ID, "stop", "json");
// Ask application to publish the command to this gateway now
publishCommand(false, null);
count = 0;
// wait for sometime before checking
while(callback.commandReceived == false && count++ <= 5) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
assertFalse("The command should not be received by gateway", callback.commandReceived);
}
private void publishCommand(boolean gateway, String cmdName) {
/**
* Load device properties
*/
Properties props = new Properties();
try {
props.load(GatewayCommandSubscriptionTest.class.getResourceAsStream(APPLICATION_PROPERTIES_FILE));
} catch (IOException e1) {
System.err.println("Not able to read the properties file, exiting..");
System.exit(-1);
}
ApplicationClient myAppClient = null;
try {
//Instantiate the class by passing the properties file
myAppClient = new ApplicationClient(props);
myAppClient.connect();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
JsonObject data = new JsonObject();
data.addProperty("name", "stop-rotation");
data.addProperty("delay", 0);
if(cmdName == null) {
// use default command name
cmdName = "stop";
}
if(gateway) {
//Registered flow allows 0, 1 and 2 QoS
myAppClient.publishCommand(GATEWAY_DEVICE_TYPE, GATEWAY_DEVICE_ID, cmdName, data);
} else {
myAppClient.publishCommand(DEVICE_TYPE, SIMULATOR_DEVICE_ID, cmdName, data);
}
myAppClient.disconnect();
}
//Implement the CommandCallback class to provide the way in which you want the command to be handled
private static class GatewayCommandCallback implements GatewayCallback{
private boolean commandReceived = false;
/**
* This method is invoked by the library whenever there is command matching the subscription criteria
*/
@Override
public void processCommand(com.ibm.iotf.client.gateway.Command cmd) {
commandReceived = true;
System.out.println("Received command, name = "+cmd.getCommand() +
", format = " + cmd.getFormat() + ", Payload = "+cmd.getPayload() + ", time = "+cmd.getTimestamp() +
", deviceId = "+cmd.getDeviceId() + ", deviceType = "+cmd.getDeviceType());
}
@Override
public void processNotification(Notification notification) {
// TODO Auto-generated method stub
}
private void clear() {
commandReceived = false;
}
}
private static String trimedValue(String value) {
if(value != null) {
return value.trim();
}
return value;
}
}