diff --git a/components/device-types/pom.xml b/components/device-types/pom.xml
new file mode 100644
index 000000000..499c62ac6
--- /dev/null
+++ b/components/device-types/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ carbon-device-mgt-plugins-parent
+ 6.0.16-SNAPSHOT
+ ../../pom.xml
+
+
+ 4.0.0
+ device-types
+ pom
+ WSO2 Carbon - IoT Plugins
+ http://wso2.org
+
+
+ virtual-fire-alarm-plugin
+
+
+
+
+
+
+ org.apache.felix
+ maven-scr-plugin
+ 1.7.2
+
+
+ generate-scr-scrdescriptor
+
+ scr
+
+
+
+
+
+
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml
new file mode 100644
index 000000000..c2160bfcc
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml
@@ -0,0 +1,236 @@
+
+
+
+
+ 4.0.0
+
+
+ virtual-fire-alarm-plugin
+ org.wso2.carbon.devicemgt-plugins
+ 6.0.16-SNAPSHOT
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl
+ WSO2 Carbon - IoT Server VirtualFireAlarm Agent
+ WSO2 Carbon - VirtualFireAlarm Device Agent Implementation
+ http://wso2.org
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ UTF-8
+
+ ${wso2.maven.compiler.target}
+
+ 2.3.2
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.Bootstrap
+
+
+
+
+ jar-with-dependencies
+
+ wso2-firealarm-virtual-agent
+ false
+
+
+
+ make-assembly
+
+ package
+
+
+ single
+
+
+
+
+
+
+
+
+
+
+
+
+ log4j
+ log4j
+ ${log4j.version}
+
+
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${jetty.version}
+
+
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ ${paho.mqtt.version}
+
+
+
+
+ org.igniterealtime.smack.wso2
+ smack
+ ${smack.wso2.version}
+
+
+ org.igniterealtime.smack.wso2
+ smackx
+ ${smackx.wso2.version}
+
+
+
+
+ org.bouncycastle.wso2
+ bcprov-jdk15on
+ ${bcprov.wso2.version}
+
+
+ org.bouncycastle.wso2
+ bcpkix-jdk15on
+ ${bcpkix.wso2.version}
+
+
+
+
+ com.google.code.jscep.wso2
+ jscep
+ ${jscep.version}
+
+
+
+ commons-codec
+ commons-codec
+
+
+
+ commons-lang
+ commons-lang
+ ${commons-lang.version}
+
+
+
+ commons-logging
+ commons-logging
+ ${common-logging.version}
+
+
+
+ commons-io
+ commons-io
+ ${commons.io}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+
+
+
+ org.json.wso2
+ json
+
+
+
+ commons-configuration
+ commons-configuration
+ 1.10
+
+
+
+
+
+
+
+
+ wso2-nexus
+ WSO2 internal Repository
+ http://maven.wso2.org/nexus/content/groups/wso2-public/
+
+ true
+ daily
+ ignore
+
+
+
+ wso2-maven2-repository
+ http://dist.wso2.org/maven2
+
+
+
+
+
+
+ 1.7
+ 1.7
+
+
+ 8.1.3.v20120416
+
+
+ 1.0.2
+
+
+ 3.0.4.wso2v1
+ 3.0.4.wso2v1
+
+
+ 1.49.wso2v1
+ 1.49.wso2v1
+
+
+ 2.0.2.wso2v2
+
+
+ 1.2.17
+ 1.2
+ 2.4
+ 1.7
+ 2.6
+
+
+ 1.7.13
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java
new file mode 100644
index 000000000..63d4b2595
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent;
+
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+
+public class Bootstrap {
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) {
+ System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
+ System.setProperty("org.apache.commons.logging.simplelog.defaultlog", "info");
+ System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
+ System.setProperty("org.apache.commons.logging.simplelog.dateTimeFormat", "HH:mm:ss");
+ AgentManager.getInstance().init();
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java
new file mode 100644
index 000000000..ead68c528
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.http;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.http.HTTPTransportHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.ProtocolException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public class FireAlarmHTTPCommunicator extends HTTPTransportHandler {
+ private static final Log log = LogFactory.getLog(FireAlarmHTTPCommunicator.class);
+
+ private ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
+ private ScheduledFuture> dataPushServiceHandler;
+ private ScheduledFuture> connectorServiceHandler;
+
+ public FireAlarmHTTPCommunicator() {
+ super();
+ }
+
+ public FireAlarmHTTPCommunicator(int port) {
+ super(port);
+ }
+
+ public FireAlarmHTTPCommunicator(int port, int reconnectionInterval) {
+ super(port, reconnectionInterval);
+ }
+
+ public ScheduledFuture> getDataPushServiceHandler() {
+ return dataPushServiceHandler;
+ }
+
+ public void connect() {
+ Runnable connect = new Runnable() {
+ public void run() {
+ if (!isConnected()) {
+ try {
+ processIncomingMessage();
+ server.start();
+ registerThisDevice();
+ publishDeviceData();
+ log.info("HTTP Server started at port: " + port);
+
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.warn("Unable to 'START' HTTP server. Will retry after " +
+ timeoutInterval / 1000 + " seconds.");
+ }
+ }
+ }
+ }
+ };
+
+ connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval,
+ TimeUnit.MILLISECONDS);
+ }
+
+
+ @Override
+ public void processIncomingMessage() {
+ server.setHandler(new AbstractHandler() {
+ public void handle(String s, Request request, HttpServletRequest
+ httpServletRequest,
+ HttpServletResponse httpServletResponse)
+ throws IOException, ServletException {
+ httpServletResponse.setContentType("text/html;charset=utf-8");
+ httpServletResponse.setStatus(HttpServletResponse.SC_OK);
+ request.setHandled(true);
+
+ AgentManager agentManager = AgentManager.getInstance();
+ String pathContext = request.getPathInfo();
+ String separator = File.separatorChar=='\\' ? "\\\\" : File.separator ;
+
+ if (pathContext.toUpperCase().contains(
+ separator + AgentConstants.TEMPERATURE_CONTROL)) {
+ httpServletResponse.getWriter().println(
+ agentManager.getTemperature());
+
+ } else if (pathContext.toUpperCase().contains(
+ separator + AgentConstants.HUMIDITY_CONTROL)) {
+ httpServletResponse.getWriter().println(
+ agentManager.getHumidity());
+
+ } else if (pathContext.toUpperCase().contains(
+ separator + AgentConstants.BULB_CONTROL)) {
+ String[] pathVariables = pathContext.split(separator);
+
+ if (pathVariables.length != 3) {
+ httpServletResponse.getWriter().println(
+ "Invalid BULB-control received by the device. Need to be in " +
+ "'{host}:{port}/BULB/{ON|OFF}' format.");
+ return;
+ }
+
+ String switchState = pathVariables[2];
+
+ if (switchState == null) {
+ httpServletResponse.getWriter().println(
+ "Please specify switch-status of the BULB.");
+ } else {
+ boolean status = switchState.toUpperCase().equals(
+ AgentConstants.CONTROL_ON);
+ agentManager.changeAlarmStatus(status);
+ httpServletResponse.getWriter().println("Bulb is " + (status ?
+ AgentConstants.CONTROL_ON : AgentConstants.CONTROL_OFF));
+ }
+ } else {
+ httpServletResponse.getWriter().println(
+ "Invalid control command received by the device.");
+ }
+ }
+ });
+ }
+
+ @Override
+ public void publishDeviceData() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ int publishInterval = agentManager.getPushInterval();
+ final String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner();
+ final String deviceID = agentManager.getAgentConfigs().getDeviceId();
+ boolean simulationMode = false;
+ int duration = 2 * 60;
+ int frequency = 5;
+
+ Runnable pushDataRunnable = new Runnable() {
+ @Override
+ public void run() {
+
+ String pushDataPayload = String.format(AgentConstants.PUSH_DATA_PAYLOAD, deviceOwner,
+ deviceID, (agentManager.getDeviceIP() + ":" + port),
+ agentManager.getTemperature());
+ executeDataPush(pushDataPayload);
+ }
+ };
+
+ if (!simulationMode) {
+ dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval,
+ publishInterval,
+ TimeUnit.SECONDS);
+ } else {
+ String pushDataPayload = String.format(AgentConstants.PUSH_SIMULATION_DATA_PAYLOAD, deviceOwner,
+ deviceID, (agentManager.getDeviceIP() + ":" + port),
+ agentManager.getTemperature(), true, duration, frequency);
+ executeDataPush(pushDataPayload);
+
+ }
+ }
+
+
+ private void executeDataPush(String pushDataPayload) {
+ AgentManager agentManager = AgentManager.getInstance();
+ String pushDataEndPointURL = agentManager.getPushDataAPIEP();
+ HttpURLConnection httpConnection;
+ int responseCode = -1;
+
+ try {
+ httpConnection = TransportUtils.getHttpConnection(agentManager.getPushDataAPIEP());
+ httpConnection.setRequestMethod(AgentConstants.HTTP_POST);
+ httpConnection.setRequestProperty("Authorization",
+ "Bearer " + agentManager.getAgentConfigs().getAuthToken());
+ httpConnection.setRequestProperty("Content-Type", AgentConstants.APPLICATION_JSON);
+
+ httpConnection.setDoOutput(true);
+ DataOutputStream dataOutPutWriter = new DataOutputStream(httpConnection.getOutputStream());
+ dataOutPutWriter.writeBytes(pushDataPayload);
+ dataOutPutWriter.flush();
+ dataOutPutWriter.close();
+
+ responseCode = httpConnection.getResponseCode();
+ httpConnection.disconnect();
+
+ log.info(AgentConstants.LOG_APPENDER + "Message - '" + pushDataPayload +
+ "' was published to server at: " + httpConnection.getURL());
+
+ } catch (ProtocolException exception) {
+ String errorMsg =
+ "Protocol specific error occurred when trying to set method to " +
+ AgentConstants.HTTP_POST + " for:" + pushDataEndPointURL;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+
+ } catch (IOException exception) {
+ String errorMsg =
+ "An IO error occurred whilst trying to get the response code from: " +
+ pushDataEndPointURL + " for a " + AgentConstants.HTTP_POST + " method.";
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+
+ } catch (TransportHandlerException exception) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Error encountered whilst trying to create HTTP-Connection to IoT-Server EP at: " +
+ pushDataEndPointURL);
+ }
+
+ if (responseCode == HttpStatus.CONFLICT_409 ||
+ responseCode == HttpStatus.PRECONDITION_FAILED_412) {
+ log.warn(AgentConstants.LOG_APPENDER +
+ "DeviceIP is being Re-Registered due to Push-Data failure with response code: " +
+ responseCode);
+ registerThisDevice();
+
+ } else if (responseCode != HttpStatus.NO_CONTENT_204) {
+ if (log.isDebugEnabled()) {
+ log.error(AgentConstants.LOG_APPENDER + "Status Code: " + responseCode +
+ " encountered whilst trying to Push-Device-Data to IoT Server at: " +
+ agentManager.getPushDataAPIEP());
+ }
+ agentManager.updateAgentStatus(AgentConstants.SERVER_NOT_RESPONDING);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug(AgentConstants.LOG_APPENDER + "Push-Data call with payload - " + pushDataPayload +
+ ", to IoT Server returned status " + responseCode);
+ }
+ }
+
+ @Override
+ public void disconnect() {
+ Runnable stopConnection = new Runnable() {
+ public void run() {
+ while (isConnected()) {
+ try {
+ dataPushServiceHandler.cancel(true);
+ connectorServiceHandler.cancel(true);
+ closeConnection();
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.warn(AgentConstants.LOG_APPENDER + "Unable to 'STOP' HTTP server at port: " + port);
+ }
+
+ try {
+ Thread.sleep(timeoutInterval);
+ } catch (InterruptedException e1) {
+ log.error(
+ AgentConstants.LOG_APPENDER + "HTTP-Termination: Thread Sleep Interrupt Exception");
+ }
+ }
+ }
+ }
+ };
+
+ Thread terminatorThread = new Thread(stopConnection);
+ terminatorThread.setDaemon(true);
+ terminatorThread.start();
+ }
+
+ @Override
+ public void processIncomingMessage(Object message, String... messageParams) {
+
+ }
+
+ @Override
+ public void publishDeviceData(String... publishData) {
+
+ }
+
+ public void registerThisDevice() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ agentManager.updateAgentStatus("Registering...");
+
+ final Runnable ipRegistration = new Runnable() {
+ @Override
+ public void run() {
+ while (isConnected()) {
+ try {
+ int responseCode = registerDeviceIP(
+ agentManager.getAgentConfigs().getDeviceOwner(),
+ agentManager.getAgentConfigs().getDeviceId());
+
+ if (responseCode == HttpStatus.OK_200) {
+ agentManager.updateAgentStatus(AgentConstants.REGISTERED);
+ break;
+ } else {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Device Registration with IoT Server at:" + " " +
+ agentManager.getIpRegistrationEP() +
+ " failed with response - '" + responseCode + ":" +
+ HttpStatus.getMessage(responseCode) + "'");
+ agentManager.updateAgentStatus(AgentConstants.RETRYING_TO_REGISTER);
+ }
+ } catch (AgentCoreOperationException exception) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Error encountered whilst trying to register the " +
+ "Device's IP at: " +
+ agentManager.getIpRegistrationEP() +
+ ".\nCheck whether the network-interface provided is " +
+ "accurate");
+ agentManager.updateAgentStatus(AgentConstants.REGISTRATION_FAILED);
+ }
+
+ try {
+ Thread.sleep(timeoutInterval);
+ } catch (InterruptedException e1) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Device Registration: Thread Sleep Interrupt Exception");
+ }
+ }
+ }
+ };
+
+ Thread ipRegisterThread = new Thread(ipRegistration);
+ ipRegisterThread.setDaemon(true);
+ ipRegisterThread.start();
+ }
+
+
+ /**
+ * This method calls the "Register-API" of the IoT Server in order to register the device's IP
+ * against its ID.
+ *
+ * @param deviceOwner the owner of the device by whose name the agent was downloaded.
+ * (Read from configuration file)
+ * @param deviceID the deviceId that is auto-generated whilst downloading the agent.
+ * (Read from configuration file)
+ * @return the status code of the HTTP-Post call to the Register-API of the IoT-Server
+ * @throws AgentCoreOperationException if any errors occur when an HTTPConnection session is
+ * created
+ */
+ private int registerDeviceIP(String deviceOwner, String deviceID)
+ throws AgentCoreOperationException {
+ int responseCode = -1;
+ final AgentManager agentManager = AgentManager.getInstance();
+
+ String networkInterface = agentManager.getNetworkInterface();
+ String deviceIPAddress = getDeviceIP(networkInterface);
+
+ if (deviceIPAddress == null) {
+ throw new AgentCoreOperationException(
+ "An IP address could not be retrieved for the selected network interface - '" +
+ networkInterface + ".");
+ }
+
+ agentManager.setDeviceIP(deviceIPAddress);
+ log.info(AgentConstants.LOG_APPENDER + "Device IP Address: " + deviceIPAddress);
+
+ String deviceIPRegistrationEP = agentManager.getIpRegistrationEP();
+ String registerEndpointURLString =
+ deviceIPRegistrationEP + File.separator + deviceOwner + File.separator + deviceID +
+ File.separator + deviceIPAddress + File.separator + port;
+
+ if (log.isDebugEnabled()) {
+ log.debug(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " +
+ registerEndpointURLString);
+ }
+
+ HttpURLConnection httpConnection;
+ try {
+ httpConnection = TransportUtils.getHttpConnection(registerEndpointURLString);
+ } catch (TransportHandlerException e) {
+ String errorMsg =
+ "Protocol specific error occurred when trying to fetch an HTTPConnection to:" +
+ " " + registerEndpointURLString;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException();
+ }
+
+ try {
+ httpConnection.setRequestMethod(AgentConstants.HTTP_POST);
+ httpConnection.setRequestProperty("Authorization", "Bearer " +
+ agentManager.getAgentConfigs().getAuthToken());
+ httpConnection.setDoOutput(true);
+ responseCode = httpConnection.getResponseCode();
+
+ } catch (ProtocolException exception) {
+ String errorMsg = "Protocol specific error occurred when trying to set method to " +
+ AgentConstants.HTTP_POST + " for:" + registerEndpointURLString;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, exception);
+
+ } catch (IOException exception) {
+ String errorMsg = "An IO error occurred whilst trying to get the response code from:" +
+ " " + registerEndpointURLString + " for a " + AgentConstants.HTTP_POST + " method.";
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, exception);
+ }
+
+ log.info(AgentConstants.LOG_APPENDER + "DeviceIP - " + deviceIPAddress +
+ ", registration with IoT Server at : " +
+ agentManager.getAgentConfigs().getHTTPS_ServerEndpoint() +
+ " returned status " +
+ responseCode);
+
+ return responseCode;
+ }
+
+ /*------------------------------------------------------------------------------------------*/
+ /* Utility methods relevant to creating and sending HTTP requests to the Iot-Server */
+ /*------------------------------------------------------------------------------------------*/
+
+ /**
+ * This method is used to get the IP of the device in which the agent is run on.
+ *
+ * @return the IP Address of the device
+ * @throws AgentCoreOperationException if any errors occur whilst trying to get the IP address
+ */
+ private String getDeviceIP() throws AgentCoreOperationException {
+ try {
+ return Inet4Address.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ String errorMsg = "Error encountered whilst trying to get the device IP address.";
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+ }
+
+ /**
+ * This is an overloaded method that fetches the public IPv4 address of the given network
+ * interface
+ *
+ * @param networkInterfaceName the network-interface of whose IPv4 address is to be retrieved
+ * @return the IP Address iof the device
+ * @throws AgentCoreOperationException if any errors occur whilst trying to get details of the
+ * given network interface
+ */
+ private String getDeviceIP(String networkInterfaceName) throws
+ AgentCoreOperationException {
+ String ipAddress = null;
+ try {
+ Enumeration interfaceIPAddresses = NetworkInterface.getByName(
+ networkInterfaceName).getInetAddresses();
+ for (; interfaceIPAddresses.hasMoreElements(); ) {
+ InetAddress ip = interfaceIPAddresses.nextElement();
+ ipAddress = ip.getHostAddress();
+ if (log.isDebugEnabled()) {
+ log.debug(AgentConstants.LOG_APPENDER + "IP Address: " + ipAddress);
+ }
+
+ if (TransportUtils.validateIPv4(ipAddress)) {
+ return ipAddress;
+ }
+ }
+ } catch (SocketException | NullPointerException exception) {
+ String errorMsg =
+ "Error encountered whilst trying to get IP Addresses of the network interface: " +
+ networkInterfaceName +
+ ".\nPlease check whether the name of the network interface used is correct";
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, exception);
+ }
+
+ return ipAddress;
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java
new file mode 100644
index 000000000..777671038
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.mqtt;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttSecurityException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.mqtt.MQTTTransportHandler;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+//TODO:: Lincence header, comments and SPECIFIC class name since its not generic
+public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
+
+ private static final Log log = LogFactory.getLog(FireAlarmMQTTCommunicator.class);
+
+ private ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
+ private ScheduledFuture> dataPushServiceHandler;
+ private static final String DEFAULT_PASSWORD = "";
+
+ public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType,
+ String mqttBrokerEndPoint, String subscribeTopic) {
+ super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic);
+ }
+
+ @SuppressWarnings("unused")
+ public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType,
+ String mqttBrokerEndPoint, String subscribeTopic,
+ int intervalInMillis) {
+ super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic, intervalInMillis);
+ }
+
+ public ScheduledFuture> getDataPushServiceHandler() {
+ return dataPushServiceHandler;
+ }
+
+ //TODO:: Terminate logs with a period
+ //TODO: Need to print exceptions
+ @Override
+ public void connect() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ Runnable connector = new Runnable() {
+ public void run() {
+ while (!isConnected()) {
+ try { // uudi formay 8-4-4-4-12
+ connectToQueue(agentManager.getAgentConfigs().getAuthToken().substring(0, 18),
+ agentManager.getAgentConfigs().getAuthToken().substring(19));
+ agentManager.updateAgentStatus("Connected to MQTT Queue");
+ } catch (TransportHandlerException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Connection to MQTT Broker at: " + mqttBrokerEndPoint +
+ " failed.\n Will retry in " + timeoutInterval + " milli-seconds.");
+
+ if (e.getCause() != null && e.getCause() instanceof MqttSecurityException) {
+ refreshOAuthToken((MqttSecurityException) e.getCause());
+ }
+ }
+
+ try {
+ if (isConnected()) {
+ subscribeToQueue();
+ agentManager.updateAgentStatus("Subscribed to MQTT Queue");
+ publishDeviceData();
+ }
+ } catch (TransportHandlerException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Subscription to MQTT Broker at: " +
+ mqttBrokerEndPoint + " failed");
+ agentManager.updateAgentStatus("Subscription to broker failed.");
+ }
+
+ try {
+ Thread.sleep(timeoutInterval);
+ } catch (InterruptedException ex) {
+ log.error(AgentConstants.LOG_APPENDER + "MQTT: Connect-Thread Sleep Interrupt Exception.");
+ }
+ }
+ }
+ };
+
+ Thread connectorThread = new Thread(connector);
+ connectorThread.setDaemon(true);
+ connectorThread.start();
+ }
+
+ private void refreshOAuthToken(final MqttSecurityException exception) {
+ Runnable tokenRefresher = new Runnable() {
+ public void run() {
+ String authenticationMethod = AgentUtilOperations.getAuthenticationMethod();
+
+ try {
+ if (exception.getReasonCode() == MqttSecurityException.REASON_CODE_FAILED_AUTHENTICATION &&
+ authenticationMethod.equals(AgentConstants.TOKEN_AUTHENTICATION_METHOD)) {
+ AgentUtilOperations.refreshOAuthToken();
+ }
+ } catch (AgentCoreOperationException e1) {
+ log.error(AgentConstants.LOG_APPENDER + "Token Refresh Attempt Failed. " + e1);
+ }
+ }
+ };
+
+ Thread connectorThread = new Thread(tokenRefresher);
+ connectorThread.setDaemon(true);
+ connectorThread.start();
+ }
+
+ @Override
+ public void processIncomingMessage(MqttMessage message, String... messageParams) {
+ final AgentManager agentManager = AgentManager.getInstance();
+ String tenantDomain = agentManager.getAgentConfigs().getTenantDomain();
+ String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner();
+ String deviceID = agentManager.getAgentConfigs().getDeviceId();
+ String receivedMessage;
+ String replyMessage;
+ String securePayLoad;
+
+ if (message.toString().contains("BULB:ON")) {
+ boolean stateToSwitch = true;
+ agentManager.changeAlarmStatus(stateToSwitch);
+ log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: 'ON'");
+ return;
+ } else if (message.toString().contains("BULB:OFF")) {
+ boolean stateToSwitch = false;
+ agentManager.changeAlarmStatus(stateToSwitch);
+ log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: 'OFF'");
+ return;
+ }
+
+ try {
+ receivedMessage = AgentUtilOperations.extractMessageFromPayload(message.toString());
+ log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received");
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e);
+ return;
+ }
+
+
+ String[] controlSignal = receivedMessage.split(":");
+ // message- ":" format.(ex: "BULB:ON", "TEMPERATURE", "HUMIDITY")
+
+ try {
+ switch (controlSignal[0].toUpperCase()) {
+ case AgentConstants.BULB_CONTROL:
+ boolean stateToSwitch = controlSignal[1].equals(AgentConstants.CONTROL_ON);
+ agentManager.changeAlarmStatus(stateToSwitch);
+ log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'");
+ break;
+
+ case AgentConstants.TEMPERATURE_CONTROL:
+ int currentTemperature = agentManager.getTemperature();
+
+ String replyTemperature = "Current temperature was read as: '" + currentTemperature + "C'";
+ log.info(AgentConstants.LOG_APPENDER + replyTemperature);
+
+ String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, tenantDomain, deviceID);
+
+ replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature;
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ publishToQueue(tempPublishTopic, securePayLoad);
+ break;
+
+ case AgentConstants.HUMIDITY_CONTROL:
+ int currentHumidity = agentManager.getHumidity();
+
+ String replyHumidity = "Current humidity was read as: '" + currentHumidity + "%'";
+ log.info(AgentConstants.LOG_APPENDER + replyHumidity);
+
+ String humidPublishTopic = String.format(
+ AgentConstants.MQTT_PUBLISH_TOPIC, tenantDomain, deviceID);
+
+ replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity;
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ publishToQueue(humidPublishTopic, securePayLoad);
+ break;
+
+ default:
+ log.warn(AgentConstants.LOG_APPENDER + "'" + controlSignal[0] +
+ "' is invalid and not-supported for this device-type");
+ break;
+ }
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e);
+ } catch (TransportHandlerException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "MQTT - Publishing, reply message to the MQTT Queue at: " +
+ agentManager.getAgentConfigs().getMqttBrokerEndpoint() + " failed");
+ }
+
+ }
+
+ @Override
+ public void publishDeviceData() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ int publishInterval = agentManager.getPushInterval();
+ Runnable pushDataRunnable = new Runnable() {
+ @Override
+ public void run() {
+ int currentTemperature = agentManager.getTemperature();
+ String message = "{\"event\": {\"metaData\": {\"owner\": \"" + AgentManager
+ .getInstance().getAgentConfigs().getDeviceOwner() + "\",\"deviceId\": \"" + AgentManager
+ .getInstance().getAgentConfigs().getDeviceId() + "\",\"time\": \"" +
+ System.currentTimeMillis() + "\"},\"payloadData\": { \"temperature\": " + currentTemperature + "} }}";
+
+ try {
+ String payLoad = AgentUtilOperations.prepareSecurePayLoad(message);
+
+ MqttMessage pushMessage = new MqttMessage();
+ pushMessage.setPayload(payLoad.getBytes(StandardCharsets.UTF_8));
+ pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE);
+ pushMessage.setRetained(false);
+
+ String topic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC,
+ agentManager.getAgentConfigs().getTenantDomain(),
+ agentManager.getAgentConfigs().getDeviceId());
+
+ publishToQueue(topic, pushMessage);
+ log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' published to MQTT Queue at [" +
+ agentManager.getAgentConfigs().getMqttBrokerEndpoint() + "] under topic [" +
+ topic + "]");
+
+ } catch (TransportHandlerException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Data Publish attempt to topic - [" +
+ AgentConstants.MQTT_PUBLISH_TOPIC + "] failed for payload [" + message + "]");
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e);
+ }
+ }
+ };
+
+ dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, publishInterval,
+ TimeUnit.SECONDS);
+ }
+
+
+ @Override
+ public void disconnect() {
+ Runnable stopConnection = new Runnable() {
+ public void run() {
+ while (isConnected()) {
+
+ if (dataPushServiceHandler != null) {
+ dataPushServiceHandler.cancel(true);
+ }
+
+ try {
+ closeConnection();
+
+ } catch (MqttException e) {
+ if (log.isDebugEnabled()) {
+ log.warn(AgentConstants.LOG_APPENDER +
+ "Unable to 'STOP' MQTT connection at broker at: " +
+ mqttBrokerEndPoint);
+ }
+
+ try {
+ Thread.sleep(timeoutInterval);
+ } catch (InterruptedException e1) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "MQTT-Terminator: Thread Sleep Interrupt Exception");
+ }
+ }
+ }
+ }
+ };
+
+ Thread terminatorThread = new Thread(stopConnection);
+ terminatorThread.setDaemon(true);
+ terminatorThread.start();
+ }
+
+ @Override
+ public void processIncomingMessage() {
+
+ }
+
+ @Override
+ public void publishDeviceData(String... publishData) {
+
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java
new file mode 100644
index 000000000..0780f2d84
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.xmpp;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jivesoftware.smack.packet.Message;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConfiguration;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.xmpp.XMPPTransportHandler;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public class FireAlarmXMPPCommunicator extends XMPPTransportHandler {
+
+ private static final Log log = LogFactory.getLog(FireAlarmXMPPCommunicator.class);
+
+ private ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
+ private ScheduledFuture> dataPushServiceHandler;
+ private ScheduledFuture> connectorServiceHandler;
+
+ private String username;
+ private String password;
+ private String resource;
+ private String xmppAdminJID;
+ private String xmppDeviceJID;
+
+ public FireAlarmXMPPCommunicator(String server) {
+ super(server);
+ }
+
+ public FireAlarmXMPPCommunicator(String server, int port) {
+ super(server, port);
+ }
+
+ public FireAlarmXMPPCommunicator(String server, int port, int timeout) {
+ super(server, port, timeout);
+ }
+
+ public ScheduledFuture> getDataPushServiceHandler() {
+ return dataPushServiceHandler;
+ }
+
+ @Override
+ public void connect() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ username = agentManager.getAgentConfigs().getDeviceId();
+ password = agentManager.getAgentConfigs().getAuthToken();
+ xmppDeviceJID = username + "@" + agentManager.getAgentConfigs().getXmppServerName();
+ xmppAdminJID = agentManager.getAgentConfigs().getServerJID();
+
+ Runnable connect = new Runnable() {
+ public void run() {
+ if (!isConnected()) {
+ try {
+ connectToServer();
+ } catch (TransportHandlerException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Connection to XMPP server at: " + server + " failed");
+ }
+
+ try {
+ loginToServer(username, password, resource);
+ agentManager.updateAgentStatus("Connected to XMPP Server");
+ setMessageFilterAndListener(xmppAdminJID, xmppDeviceJID, true);
+ publishDeviceData();
+ } catch (TransportHandlerException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Login to XMPP server at: " + server + " failed");
+ agentManager.updateAgentStatus("No XMPP Account for Device");
+ }
+ }
+ }
+ };
+
+ connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * This is an abstract method used for post processing the received XMPP-message. This
+ * method will be implemented as per requirement at the time of creating an object of this
+ * class.
+ *
+ * @param xmppMessage the xmpp message received by the listener.
+ */
+ @Override
+ public void processIncomingMessage(Message xmppMessage, String... messageParams) {
+ final AgentManager agentManager = AgentManager.getInstance();
+ String from = xmppMessage.getFrom();
+ String message = xmppMessage.getBody();
+ String receivedMessage;
+ String replyMessage;
+ String securePayLoad;
+
+ try {
+ receivedMessage = AgentUtilOperations.extractMessageFromPayload(message);
+ log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received");
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e);
+ return;
+ }
+
+ String[] controlSignal = receivedMessage.split(":");
+ //message- ":" format. (ex: "BULB:ON", "TEMPERATURE", "HUMIDITY")
+
+ try {
+ switch (controlSignal[0].toUpperCase()) {
+ case AgentConstants.BULB_CONTROL:
+ if (controlSignal.length != 2) {
+ replyMessage = "BULB controls need to be in the form - 'BULB:{ON|OFF}'";
+ log.warn(replyMessage);
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY");
+ break;
+ }
+
+ agentManager.changeAlarmStatus(controlSignal[1].equals(AgentConstants.CONTROL_ON));
+ log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'");
+ break;
+
+ case AgentConstants.TEMPERATURE_CONTROL:
+ int currentTemperature = agentManager.getTemperature();
+
+ String replyTemperature =
+ "The current temperature was read to be: '" + currentTemperature +
+ "C'";
+ log.info(AgentConstants.LOG_APPENDER + replyTemperature);
+
+ replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature;
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY");
+ break;
+
+ case AgentConstants.HUMIDITY_CONTROL:
+ int currentHumidity = agentManager.getHumidity();
+
+ String replyHumidity = "The current humidity was read to be: '" + currentHumidity + "%'";
+ log.info(AgentConstants.LOG_APPENDER + replyHumidity);
+
+ replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity;
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY");
+ break;
+
+ default:
+ replyMessage = "'" + controlSignal[0] + "' is invalid and not-supported for this device-type";
+ log.warn(replyMessage);
+ securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
+ sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-ERROR");
+ break;
+ }
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e);
+ }
+
+ }
+
+
+ @Override
+ public void publishDeviceData() {
+ final AgentManager agentManager = AgentManager.getInstance();
+ int publishInterval = agentManager.getPushInterval();
+
+ Runnable pushDataRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Message xmppMessage = new Message();
+
+ try {
+ int currentTemperature = agentManager.getTemperature();
+ String message = "{\"event\": {\"metaData\": {\"owner\": \"" + AgentManager
+ .getInstance().getAgentConfigs().getDeviceOwner() + "\",\"deviceId\": \"" + AgentManager
+ .getInstance().getAgentConfigs().getDeviceId() + "\",\"time\": " +
+ "0},\"payloadData\": { \"temperature\": " + currentTemperature + "} }}";
+ String payLoad = AgentUtilOperations.prepareSecurePayLoad(message);
+
+ xmppMessage.setTo(xmppAdminJID);
+ xmppMessage.setSubject(agentManager.getAgentConfigs().getTenantDomain());
+ xmppMessage.setBody(payLoad);
+ xmppMessage.setType(Message.Type.chat);
+
+ sendXMPPMessage(xmppAdminJID, xmppMessage);
+ log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' sent to XMPP JID - " +
+ "[" + xmppAdminJID + "] under subject [" + xmppMessage.getSubject() + "].");
+ } catch (AgentCoreOperationException e) {
+ log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed for XMPP JID - " +
+ "[" + xmppAdminJID + "] with subject - [" + xmppMessage.getSubject() + "].");
+ }
+ }
+ };
+
+ dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval,
+ publishInterval, TimeUnit.SECONDS);
+ }
+
+
+ @Override
+ public void disconnect() {
+ Runnable stopConnection = new Runnable() {
+ public void run() {
+
+ if (dataPushServiceHandler != null) {
+ dataPushServiceHandler.cancel(true);
+ }
+
+ if (connectorServiceHandler != null) {
+ connectorServiceHandler.cancel(true);
+ }
+
+ while (isConnected()) {
+ closeConnection();
+
+ if (log.isDebugEnabled()) {
+ log.warn(AgentConstants.LOG_APPENDER +
+ "Unable to 'STOP' connection to XMPP server at: " + server);
+ }
+
+ try {
+ Thread.sleep(timeoutInterval);
+ } catch (InterruptedException e1) {
+ log.error(AgentConstants.LOG_APPENDER + "XMPP-Terminator: Thread Sleep Interrupt Exception");
+ }
+
+ }
+ }
+ };
+
+ Thread terminatorThread = new Thread(stopConnection);
+ terminatorThread.setDaemon(true);
+ terminatorThread.start();
+ }
+
+
+ @Override
+ public void processIncomingMessage() {
+
+ }
+
+ @Override
+ public void publishDeviceData(String... publishData) {
+
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java
new file mode 100644
index 000000000..7d8f1dc57
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core;
+
+/**
+ * A Configuration class that holds all the Agent specific details that are read from the
+ * 'deviceConfig.properties' file. This file is generated by the IoT-Server at the time of
+ * downloading the device agent from the IoT-Server.
+ */
+public class AgentConfiguration {
+ private String tenantDomain;
+ private String deviceOwner;
+ private String deviceId;
+ private String deviceName;
+ private String HTTPS_ServerEndpoint;
+ private String HTTP_ServerEndpoint;
+ private String apimGatewayEndpoint;
+ private String mqttBrokerEndpoint;
+ private String xmppServerEndpoint;
+ private String apiApplicationKey;
+ private String authToken;
+ private String refreshToken;
+ private int dataPushInterval;
+ private String xmppServerName;
+ private String serverJID;
+
+ public String getTenantDomain() {
+ return tenantDomain;
+ }
+
+ public void setTenantDomain(String tenantDomain) {
+ this.tenantDomain = tenantDomain;
+ }
+
+ public String getDeviceOwner() {
+ return deviceOwner;
+ }
+
+ public void setDeviceOwner(String deviceOwner) {
+ this.deviceOwner = deviceOwner;
+ }
+
+ public String getDeviceId() {
+ return deviceId;
+ }
+
+ public String getServerJID() {
+ return serverJID;
+ }
+
+ public void setServerJID(String serverJID) {
+ this.serverJID = serverJID;
+ }
+
+ public void setDeviceId(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ public String getDeviceName() {
+ return deviceName;
+ }
+
+ public void setDeviceName(String deviceName) {
+ this.deviceName = deviceName;
+ }
+
+ public String getHTTPS_ServerEndpoint() {
+ return HTTPS_ServerEndpoint;
+ }
+
+ public void setHTTPS_ServerEndpoint(String HTTPS_ServerEndpoint) {
+ this.HTTPS_ServerEndpoint = HTTPS_ServerEndpoint;
+ }
+
+ public String getHTTP_ServerEndpoint() {
+ return HTTP_ServerEndpoint;
+ }
+
+ public void setHTTP_ServerEndpoint(String HTTP_ServerEndpoint) {
+ this.HTTP_ServerEndpoint = HTTP_ServerEndpoint;
+ }
+
+ public String getApimGatewayEndpoint() {
+ return apimGatewayEndpoint;
+ }
+
+ public void setApimGatewayEndpoint(String apimGatewayEndpoint) {
+ this.apimGatewayEndpoint = apimGatewayEndpoint;
+ }
+
+ public String getMqttBrokerEndpoint() {
+ return mqttBrokerEndpoint;
+ }
+
+ public void setMqttBrokerEndpoint(String mqttBrokerEndpoint) {
+ this.mqttBrokerEndpoint = mqttBrokerEndpoint;
+ }
+
+ public String getXmppServerEndpoint() {
+ return xmppServerEndpoint;
+ }
+
+ public void setXmppServerEndpoint(String xmppServerEndpoint) {
+ this.xmppServerEndpoint = xmppServerEndpoint;
+ }
+
+ public String getApiApplicationKey() {
+ return apiApplicationKey;
+ }
+
+ public void setApiApplicationKey(String apiApplicationKey) {
+ this.apiApplicationKey = apiApplicationKey;
+ }
+
+ public String getAuthToken() {
+ return authToken;
+ }
+
+ public void setAuthToken(String authToken) {
+ this.authToken = authToken;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+
+ public int getDataPushInterval() {
+ return dataPushInterval;
+ }
+
+ public void setDataPushInterval(int dataPushInterval) {
+ this.dataPushInterval = dataPushInterval;
+ }
+
+ public String getXmppServerName() {
+ return xmppServerName;
+ }
+
+ public void setXmppServerName(String xmppServerName) {
+ this.xmppServerName = xmppServerName;
+ }
+}
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java
new file mode 100644
index 000000000..57fbc4ec4
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core;
+
+public class AgentConstants {
+ public static final String DEVICE_TYPE = "virtual_firealarm";
+ public static final String LOG_APPENDER = "AGENT_LOG:: ";
+ public static final String PROPERTIES_FILE_PATH = "";
+ public static final int DEFAULT_RETRY_THREAD_INTERVAL = 5000; // time in millis
+ public static final String TOKEN_AUTHENTICATION_METHOD = "token";
+ /* ---------------------------------------------------------------------------------------
+ IoT-Server specific information
+ --------------------------------------------------------------------------------------- */
+ public static final String DEVICE_CONTROLLER_API_EP = "/virtual_firealarm/device";
+ public static final String DEVICE_SCEP_API_EP = "/virtual_firealarm_scep";
+ public static final String DEVICE_ENROLLMENT_API_EP = "/scep";
+ public static final String DEVICE_REGISTER_API_EP = "/register";
+ public static final String DEVICE_PUSH_TEMPERATURE_API_EP = "/temperature";
+ public static final String PUSH_DATA_PAYLOAD =
+ "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\"}";
+
+ public static final String PUSH_SIMULATION_DATA_PAYLOAD =
+ "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\",\"isSimulated\":\"%s\"," +
+ "\"duration\":\"%s\",\"frequency\":\"%s\"}";
+
+ public static final String DEVICE_DETAILS_PAGE_EP = "/devicemgt/device/%s?id=%s";
+ public static final String DEVICE_ANALYTICS_PAGE_URL =
+ "/devicemgt/device/virtual_firealarm/analytics?deviceId=%s&deviceName=%s";
+
+ /* ---------------------------------------------------------------------------------------
+ HTTP Connection specific information for communicating with IoT-Server
+ --------------------------------------------------------------------------------------- */
+ public static final String HTTP_POST = "POST";
+ public static final String HTTP_GET = "GET";
+ public static final String AUTHORIZATION_HEADER = "Authorization";
+ public static final String CONTENT_TYPE_HEADER = "Content-Type";
+ public static final String APPLICATION_JSON = "application/json";
+ public static final String X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded";
+ public static final String REGISTERED = "Registered";
+ public static final String NOT_REGISTERED = "Not-Registered";
+ public static final String REGISTRATION_FAILED = "Registration Failed";
+ public static final String RETRYING_TO_REGISTER = "Registration Failed. Re-trying..";
+ public static final String SERVER_NOT_RESPONDING = "Server not responding..";
+
+ /* ---------------------------------------------------------------------------------------
+ MQTT Connection specific information
+ --------------------------------------------------------------------------------------- */
+ public static final int DEFAULT_MQTT_RECONNECTION_INTERVAL = 2; // time in seconds
+ public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
+ public static final String MQTT_SUBSCRIBE_TOPIC = "%s/" + DEVICE_TYPE + "/%s/operation/#";
+ public static final String MQTT_PUBLISH_TOPIC = "%s/" + DEVICE_TYPE + "/%s/temperature";
+
+ /* ---------------------------------------------------------------------------------------
+ Device/Agent specific properties to be read from the 'deviceConfig.properties' file
+ --------------------------------------------------------------------------------------- */
+ public static final String AGENT_PROPERTIES_FILE_NAME = "deviceConfig.properties";
+ public static final String TENANT_DOMAIN = "tenantDomain";
+ public static final String DEVICE_OWNER_PROPERTY = "owner";
+ public static final String DEVICE_ID_PROPERTY = "deviceId";
+ public static final String SERVER_JID_PROPERTY = "server-jid";
+ public static final String DEVICE_NAME_PROPERTY = "device-name";
+ public static final String SERVER_HTTPS_EP_PROPERTY = "https-ep";
+ public static final String SERVER_HTTP_EP_PROPERTY = "http-ep";
+ public static final String APIM_GATEWAY_EP_PROPERTY = "apim-ep";
+ public static final String MQTT_BROKER_EP_PROPERTY = "mqtt-ep";
+ public static final String XMPP_SERVER_EP_PROPERTY = "xmpp-ep";
+ public static final String XMPP_SERVER_NAME_PROPERTY = "xmpp-server-name";
+ public static final String API_APPLICATION_KEY = "application-key";
+ public static final String AUTH_TOKEN_PROPERTY = "auth-token";
+ public static final String REFRESH_TOKEN_PROPERTY = "refresh-token";
+ public static final String NETWORK_INTERFACE_PROPERTY = "network-interface";
+ public static final String PUSH_INTERVAL_PROPERTY = "push-interval";
+ /* ---------------------------------------------------------------------------------------
+ Default values for the Device/Agent specific configurations listed above
+ --------------------------------------------------------------------------------------- */
+ public static final String DEFAULT_NETWORK_INTERFACE = "en0";
+ public static final int DEFAULT_DATA_PUBLISH_INTERVAL = 15; // seconds
+ public static final String DEFAULT_PROTOCOL = "MQTT";
+ /* ---------------------------------------------------------------------------------------
+ Control Signal specific constants to match the request context
+ --------------------------------------------------------------------------------------- */
+ public static final String BULB_CONTROL = "BULB";
+ public static final String TEMPERATURE_CONTROL = "TEMPERATURE";
+ public static final String POLICY_SIGNAL = "POLICY";
+ public static final String HUMIDITY_CONTROL = "HUMIDITY";
+ public static final String CONTROL_ON = "ON";
+ public static final String CONTROL_OFF = "OFF";
+ public static final String AUDIO_FILE_NAME = "fireAlarmSound.mid";
+ /* ---------------------------------------------------------------------------------------
+ Communication protocol specific Strings
+ --------------------------------------------------------------------------------------- */
+ public static final String TCP_PREFIX = "tcp://";
+ public static final String HTTP_PREFIX = "http://";
+ public static final String HTTPS_PREFIX = "https://";
+ public static final String HTTP_PROTOCOL = "HTTP";
+ public static final String MQTT_PROTOCOL = "MQTT";
+ public static final String XMPP_PROTOCOL = "XMPP";
+ public static final String PROTOCOL_PROPERTY = "Protocol";
+ public static final String HOST_PROPERTY = "Host";
+ public static final String PORT_PROPERTY = "Port";
+
+ /* ---------------------------------------------------------------------------------------
+ Keystore specific strings for the device trustStore
+ --------------------------------------------------------------------------------------- */
+ public static final String DEVICE_KEYSTORE_TYPE = "JKS";
+ public static final String DEVICE_KEYSTORE = "virtual_firealarm.jks";
+ public static final String DEVICE_KEYSTORE_PASSWORD = "wso2@virtual_firealarm";
+ public static final String DEVICE_PRIVATE_KEY_ALIAS = "virtual_firealarm_key";
+ public static final String DEVICE_CERT_ALIAS = "virtual_firealarm_cert";
+ public static final String SERVER_CA_CERT_ALIAS = "ca_iotServer";
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java
new file mode 100644
index 000000000..df3435c27
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.http.FireAlarmHTTPCommunicator;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.mqtt.FireAlarmMQTTCommunicator;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.xmpp.FireAlarmXMPPCommunicator;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment.EnrollmentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.VirtualHardwareManager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AgentManager {
+
+ private static final Log log = LogFactory.getLog(AgentManager.class);
+ private static AgentManager agentManager;
+ private String rootPath = "";
+
+ private boolean deviceReady = false;
+ private boolean isAlarmOn = false;
+
+ private String deviceName, agentStatus;
+
+ private int pushInterval; // seconds
+ private String prevProtocol, protocol;
+
+ private String networkInterface;
+ private List interfaceList, protocolList;
+ private Map agentCommunicator;
+
+ private AgentConfiguration agentConfigs;
+
+ private String deviceIP;
+ private String enrollmentEP;
+ private String ipRegistrationEP;
+ private String pushDataAPIEP;
+
+ private AgentManager() {
+ }
+
+ public static AgentManager getInstance() {
+ if (agentManager == null) {
+ agentManager = new AgentManager();
+ }
+ return agentManager;
+ }
+
+ public void init() {
+
+ agentCommunicator = new HashMap<>();
+ // Read IoT-Server specific configurations from the 'deviceConfig.properties' file
+ try {
+ this.agentConfigs = AgentUtilOperations.readIoTServerConfigs();
+ } catch (AgentCoreOperationException e) {
+ log.error("Reading device configuration from configuration file failed:\n");
+ log.error(e);
+ System.exit(0);
+ }
+
+ // Initialise IoT-Server URL endpoints from the configuration read from file
+ AgentUtilOperations.initializeServerEndPoints();
+ // Set the hostNameVerifier to the APIM-Server IPAddress to enable HTTPS handshake
+ AgentUtilOperations.setHTTPSConfigurations();
+
+ String analyticsPageContext = String.format(AgentConstants.DEVICE_ANALYTICS_PAGE_URL,
+ agentConfigs.getDeviceId(),
+ agentConfigs.getDeviceName());
+
+ String controlPageContext = String.format(AgentConstants.DEVICE_DETAILS_PAGE_EP,
+ AgentConstants.DEVICE_TYPE,
+ agentConfigs.getDeviceId());
+
+ this.agentStatus = AgentConstants.NOT_REGISTERED;
+ this.deviceName = this.agentConfigs.getDeviceName();
+
+ this.pushInterval = this.agentConfigs.getDataPushInterval();
+ this.networkInterface = AgentConstants.DEFAULT_NETWORK_INTERFACE;
+
+ this.protocol = AgentConstants.DEFAULT_PROTOCOL;
+ this.prevProtocol = protocol;
+
+ Map xmppIPPortMap;
+ try {
+ xmppIPPortMap = TransportUtils.getHostAndPort(agentConfigs.getXmppServerEndpoint());
+ String xmppServer = xmppIPPortMap.get("Host");
+ int xmppPort = Integer.parseInt(xmppIPPortMap.get("Port"));
+
+ TransportHandler xmppCommunicator = new FireAlarmXMPPCommunicator(xmppServer, xmppPort);
+ agentCommunicator.put(AgentConstants.XMPP_PROTOCOL, xmppCommunicator);
+
+ } catch (TransportHandlerException e) {
+ log.info("XMPP Endpoint String - " + agentConfigs.getXmppServerEndpoint() +
+ ", provided in the configuration file is invalid. XMPP is not configured.");
+ }
+ String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC, agentConfigs.getTenantDomain(),
+ agentConfigs.getDeviceId());
+
+// TransportHandler httpCommunicator = new FireAlarmHTTPCommunicator();
+ TransportHandler mqttCommunicator = new FireAlarmMQTTCommunicator(agentConfigs.getDeviceOwner(),
+ agentConfigs.getDeviceId(),
+ agentConfigs.getMqttBrokerEndpoint(),
+ mqttTopic);
+
+// agentCommunicator.put(AgentConstants.HTTP_PROTOCOL, httpCommunicator);
+ agentCommunicator.put(AgentConstants.MQTT_PROTOCOL, mqttCommunicator);
+
+ try {
+ interfaceList = new ArrayList<>(TransportUtils.getInterfaceIPMap().keySet());
+ protocolList = new ArrayList<>(agentCommunicator.keySet());
+ } catch (TransportHandlerException e) {
+ log.error("An error occurred whilst retrieving all NetworkInterface-IP mappings");
+ }
+
+ //Initializing hardware at that point
+ //AgentManger.setDeviceReady() method should invoked from hardware after initialization
+ VirtualHardwareManager.getInstance().init();
+
+ //Wait till hardware get ready
+ while (!deviceReady) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ log.info(AgentConstants.LOG_APPENDER + "Sleep error in 'device ready-flag' checking thread");
+ }
+ }
+
+// try {
+// if (!EnrollmentManager.getInstance().isEnrolled()) {
+// EnrollmentManager.getInstance().beginEnrollmentFlow();
+// }
+// } catch (AgentCoreOperationException e) {
+// log.error("Device Enrollment Failed:\n");
+// log.error(e);
+// System.exit(0);
+// }
+
+ //Start agent communication
+ agentCommunicator.get(protocol).connect();
+ }
+
+ private void switchCommunicator(String stopProtocol, String startProtocol) {
+ agentCommunicator.get(stopProtocol).disconnect();
+
+ while (agentCommunicator.get(stopProtocol).isConnected()) {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ log.info(AgentConstants.LOG_APPENDER +
+ "Sleep error in 'Switch-Communicator' Thread's shutdown wait.");
+ }
+ }
+
+ agentCommunicator.get(startProtocol).connect();
+ }
+
+ public void setInterface(int interfaceId) {
+ if (interfaceId != -1) {
+ String newInterface = interfaceList.get(interfaceId);
+
+ if (!newInterface.equals(networkInterface)) {
+ networkInterface = newInterface;
+
+ if (protocol.equals(AgentConstants.HTTP_PROTOCOL) && !protocol.equals(
+ prevProtocol)) {
+ switchCommunicator(prevProtocol, protocol);
+ }
+ }
+ }
+ }
+
+ public void setProtocol(int protocolId) {
+ if (protocolId != -1) {
+ String newProtocol = protocolList.get(protocolId);
+
+ if (!protocol.equals(newProtocol)) {
+ prevProtocol = protocol;
+ protocol = newProtocol;
+ switchCommunicator(prevProtocol, protocol);
+ }
+ }
+ }
+
+ public void changeAlarmStatus(boolean isOn) {
+ VirtualHardwareManager.getInstance().changeAlarmStatus(isOn);
+ isAlarmOn = isOn;
+ }
+
+ public void updateAgentStatus(String status) {
+ this.agentStatus = status;
+ }
+
+ /*------------------------------------------------------------------------------------------*/
+ /* Getter and Setter Methods for the private variables */
+ /*------------------------------------------------------------------------------------------*/
+
+ public void setRootPath(String rootPath) {
+ this.rootPath = rootPath;
+ }
+
+ public String getRootPath() {
+ return rootPath;
+ }
+
+ public void setDeviceReady(boolean deviceReady) {
+ this.deviceReady = deviceReady;
+ }
+
+ public AgentConfiguration getAgentConfigs() {
+ return agentConfigs;
+ }
+
+ public String getDeviceIP() {
+ return deviceIP;
+ }
+
+ public void setDeviceIP(String deviceIP) {
+ this.deviceIP = deviceIP;
+ }
+
+ public String getEnrollmentEP() {
+ return enrollmentEP;
+ }
+
+ public void setEnrollmentEP(String enrollmentEP) {
+ this.enrollmentEP = enrollmentEP;
+ }
+
+ public String getIpRegistrationEP() {
+ return ipRegistrationEP;
+ }
+
+ public void setIpRegistrationEP(String ipRegistrationEP) {
+ this.ipRegistrationEP = ipRegistrationEP;
+ }
+
+ public String getPushDataAPIEP() {
+ return pushDataAPIEP;
+ }
+
+ public void setPushDataAPIEP(String pushDataAPIEP) {
+ this.pushDataAPIEP = pushDataAPIEP;
+ }
+
+ public String getDeviceName() {
+ return deviceName;
+ }
+
+ public String getNetworkInterface() {
+ return networkInterface;
+ }
+
+ public String getAgentStatus() {
+ return agentStatus;
+ }
+
+ public int getPushInterval() {
+ return pushInterval;
+ }
+
+ public void setPushInterval(int pushInterval) {
+ this.pushInterval = pushInterval;
+ TransportHandler transportHandler = agentCommunicator.get(protocol);
+
+ switch (protocol) {
+ case AgentConstants.HTTP_PROTOCOL:
+ ((FireAlarmHTTPCommunicator) transportHandler).getDataPushServiceHandler()
+ .cancel(true);
+ break;
+ case AgentConstants.MQTT_PROTOCOL:
+ ((FireAlarmMQTTCommunicator) transportHandler).getDataPushServiceHandler()
+ .cancel(true);
+ break;
+ case AgentConstants.XMPP_PROTOCOL:
+ ((FireAlarmXMPPCommunicator) transportHandler).getDataPushServiceHandler()
+ .cancel(true);
+ break;
+ default:
+ log.warn("Unknown protocol " + protocol);
+ }
+ transportHandler.publishDeviceData();
+
+ if (log.isDebugEnabled()) {
+ log.debug("The Data Publish Interval was changed to: " + pushInterval);
+ }
+ }
+
+ public List getInterfaceList() {
+ return interfaceList;
+ }
+
+ public List getProtocolList() {
+ return protocolList;
+ }
+
+ /**
+ * Get temperature reading from device
+ *
+ * @return Temperature
+ */
+ public int getTemperature() {
+ return VirtualHardwareManager.getInstance().getTemperature();
+ }
+
+ /**
+ * Get humidity reading from device
+ *
+ * @return Humidity
+ */
+ public int getHumidity() {
+ return VirtualHardwareManager.getInstance().getHumidity();
+ }
+
+ public boolean isAlarmOn() {
+ return isAlarmOn;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java
new file mode 100644
index 000000000..fa2a59275
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.jetty.http.HttpStatus;
+import org.json.JSONObject;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment.EnrollmentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.CommunicationUtils;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Properties;
+
+/**
+ * This class contains all the core operations of the FireAlarm agent that are common to both
+ * Virtual and Real Scenarios. These operations include, connecting to and subscribing to an MQTT
+ * queue and to a XMPP Server. Pushing temperature data to the IoT-Server at timely intervals.
+ * Reading device specific configuration from a configs file etc....
+ */
+public class AgentUtilOperations {
+
+ private static final Log log = LogFactory.getLog(AgentUtilOperations.class);
+ private static final String JSON_MESSAGE_KEY = "Msg";
+ private static final String JSON_SIGNATURE_KEY = "Sig";
+ private static final String JSON_SERIAL_KEY = "SerialNumber";
+
+ /**
+ * This method reads the agent specific configurations for the device from the
+ * "deviceConfigs.properties" file found at /repository/conf folder.
+ * If the properties file is not found in the specified path, then the configuration values
+ * are set to the default ones in the 'AgentConstants' class.
+ *
+ * @return an object of type 'AgentConfiguration' which contains all the necessary
+ * configuration attributes
+ */
+ public static AgentConfiguration readIoTServerConfigs() throws AgentCoreOperationException {
+ AgentManager agentManager = AgentManager.getInstance();
+ AgentConfiguration iotServerConfigs = new AgentConfiguration();
+ Properties properties = new Properties();
+ InputStream propertiesInputStream = null;
+ String propertiesFileName = AgentConstants.AGENT_PROPERTIES_FILE_NAME;
+ String rootPath = "";
+
+ try {
+ ClassLoader loader = AgentUtilOperations.class.getClassLoader();
+ URL path = loader.getResource(propertiesFileName);
+
+ if (path != null) {
+ log.info(AgentConstants.LOG_APPENDER + path);
+ rootPath = path.getPath().replace("wso2-firealarm-virtual-agent.jar!/deviceConfig.properties", "")
+ .replace("jar:", "").replace("file:", "");
+
+ rootPath = URLDecoder.decode(rootPath, StandardCharsets.UTF_8.toString());
+ agentManager.setRootPath(rootPath);
+
+ String deviceConfigFilePath = rootPath + AgentConstants.AGENT_PROPERTIES_FILE_NAME;
+ propertiesInputStream = new FileInputStream(deviceConfigFilePath);
+
+ //load a properties file from class path, inside static method
+ properties.load(propertiesInputStream);
+
+ iotServerConfigs.setTenantDomain(properties.getProperty(
+ AgentConstants.TENANT_DOMAIN));
+ iotServerConfigs.setDeviceOwner(properties.getProperty(
+ AgentConstants.DEVICE_OWNER_PROPERTY));
+ iotServerConfigs.setDeviceId(properties.getProperty(
+ AgentConstants.DEVICE_ID_PROPERTY));
+ iotServerConfigs.setServerJID(properties.getProperty(
+ AgentConstants.SERVER_JID_PROPERTY));
+ iotServerConfigs.setDeviceName(properties.getProperty(
+ AgentConstants.DEVICE_NAME_PROPERTY));
+ iotServerConfigs.setHTTPS_ServerEndpoint(properties.getProperty(
+ AgentConstants.SERVER_HTTPS_EP_PROPERTY));
+ iotServerConfigs.setHTTP_ServerEndpoint(properties.getProperty(
+ AgentConstants.SERVER_HTTP_EP_PROPERTY));
+ iotServerConfigs.setApimGatewayEndpoint(properties.getProperty(
+ AgentConstants.APIM_GATEWAY_EP_PROPERTY));
+ iotServerConfigs.setMqttBrokerEndpoint(properties.getProperty(
+ AgentConstants.MQTT_BROKER_EP_PROPERTY));
+ iotServerConfigs.setXmppServerEndpoint(properties.getProperty(
+ AgentConstants.XMPP_SERVER_EP_PROPERTY));
+ iotServerConfigs.setXmppServerName(properties.getProperty(
+ AgentConstants.XMPP_SERVER_NAME_PROPERTY));
+ iotServerConfigs.setApiApplicationKey(properties.getProperty(
+ AgentConstants.API_APPLICATION_KEY));
+ iotServerConfigs.setAuthToken(properties.getProperty(
+ AgentConstants.AUTH_TOKEN_PROPERTY));
+ iotServerConfigs.setRefreshToken(properties.getProperty(
+ AgentConstants.REFRESH_TOKEN_PROPERTY));
+ iotServerConfigs.setDataPushInterval(Integer.parseInt(properties.getProperty(
+ AgentConstants.PUSH_INTERVAL_PROPERTY)));
+
+ log.info(AgentConstants.LOG_APPENDER + "Tenant Domain: " +
+ iotServerConfigs.getTenantDomain());
+ log.info(AgentConstants.LOG_APPENDER + "Device Owner: " +
+ iotServerConfigs.getDeviceOwner());
+ log.info(AgentConstants.LOG_APPENDER + "Device ID: " +
+ iotServerConfigs.getDeviceId());
+ log.info(AgentConstants.LOG_APPENDER + "Device Name: " +
+ iotServerConfigs.getDeviceName());
+ log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTPS EndPoint: " +
+ iotServerConfigs.getHTTPS_ServerEndpoint());
+ log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTP EndPoint: " +
+ iotServerConfigs.getHTTP_ServerEndpoint());
+ log.info(AgentConstants.LOG_APPENDER + "API-Manager Gateway EndPoint: " +
+ iotServerConfigs.getApimGatewayEndpoint());
+ log.info(AgentConstants.LOG_APPENDER + "MQTT Broker EndPoint: " +
+ iotServerConfigs.getMqttBrokerEndpoint());
+ log.info(AgentConstants.LOG_APPENDER + "XMPP Server EndPoint: " +
+ iotServerConfigs.getXmppServerEndpoint());
+ log.info(AgentConstants.LOG_APPENDER + "Base64Encoded API Application Key: " +
+ iotServerConfigs.getApiApplicationKey());
+ log.info(AgentConstants.LOG_APPENDER + "Authentication Token: " +
+ iotServerConfigs.getAuthToken());
+ log.info(AgentConstants.LOG_APPENDER + "Refresh Token: " +
+ iotServerConfigs.getRefreshToken());
+ log.info(AgentConstants.LOG_APPENDER + "Data Push Interval: " +
+ iotServerConfigs.getDataPushInterval());
+ log.info(AgentConstants.LOG_APPENDER + "XMPP Server Name: " +
+ iotServerConfigs.getXmppServerName());
+ } else {
+ throw new AgentCoreOperationException(
+ "Failed to load path of resource [" + propertiesFileName + "] from this classpath.");
+ }
+ } catch (FileNotFoundException ex) {
+ String errorMsg = "[" + propertiesFileName + "] file not found at: " + rootPath;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg);
+
+ } catch (IOException ex) {
+ String errorMsg = "Error occurred whilst trying to fetch [" + propertiesFileName + "] from: " +
+ AgentConstants.PROPERTIES_FILE_PATH;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg);
+ } finally {
+ if (propertiesInputStream != null) {
+ try {
+ propertiesInputStream.close();
+ } catch (IOException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Error occurred whilst trying to close InputStream resource used to read the '" +
+ propertiesFileName + "' file");
+ }
+ }
+ }
+ return iotServerConfigs;
+ }
+
+ /**
+ * This method constructs the URLs for each of the API Endpoints called by the device agent
+ * Ex: Register API, Push-Data API
+ */
+ public static void initializeServerEndPoints() {
+ AgentManager agentManager = AgentManager.getInstance();
+ String serverSecureEndpoint = agentManager.getAgentConfigs().getHTTPS_ServerEndpoint();
+ String serverUnSecureEndpoint = agentManager.getAgentConfigs().getHTTP_ServerEndpoint();
+ String backEndContext =AgentConstants.DEVICE_CONTROLLER_API_EP;
+ String scepBackEndContext = AgentConstants.DEVICE_SCEP_API_EP;
+
+ String deviceControllerAPIEndpoint = serverSecureEndpoint + backEndContext;
+
+ String deviceEnrollmentEndpoint =
+ serverUnSecureEndpoint + scepBackEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP;
+ agentManager.setEnrollmentEP(deviceEnrollmentEndpoint);
+
+ String registerEndpointURL =
+ deviceControllerAPIEndpoint + AgentConstants.DEVICE_REGISTER_API_EP;
+ agentManager.setIpRegistrationEP(registerEndpointURL);
+
+ String pushDataEndPointURL =
+ deviceControllerAPIEndpoint + AgentConstants.DEVICE_PUSH_TEMPERATURE_API_EP;
+ agentManager.setPushDataAPIEP(pushDataEndPointURL);
+
+ log.info(AgentConstants.LOG_APPENDER + "IoT Server's Device Controller API Endpoint: " +
+ deviceControllerAPIEndpoint);
+ log.info(AgentConstants.LOG_APPENDER + "Device Enrollment EndPoint: " +
+ registerEndpointURL);
+ log.info(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " +
+ registerEndpointURL);
+ log.info(AgentConstants.LOG_APPENDER + "Push-Data API EndPoint: " + pushDataEndPointURL);
+ }
+
+ public static void setHTTPSConfigurations() {
+ String apimEndpoint = AgentManager.getInstance().getAgentConfigs().getApimGatewayEndpoint();
+ System.setProperty("javax.net.ssl.trustStore", AgentConstants.DEVICE_KEYSTORE);
+ System.setProperty("javax.net.ssl.trustStorePassword", AgentConstants.DEVICE_KEYSTORE_PASSWORD);
+
+ try {
+ final String apimHost = TransportUtils.getHostAndPort(apimEndpoint).get(AgentConstants.HOST_PROPERTY);
+
+ HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
+ public boolean verify(String hostname, SSLSession session) {
+ return hostname.equals(apimHost);
+ }
+ });
+ } catch (TransportHandlerException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Failed to set HTTPS HostNameVerifier to the APIMServer-Host using the APIM-Endpoint " +
+ "string [" + apimEndpoint + "].");
+ log.error(AgentConstants.LOG_APPENDER + e);
+ }
+ }
+
+ public static String prepareSecurePayLoad(String message) throws AgentCoreOperationException {
+ if (EnrollmentManager.getInstance().isEnrolled()) {
+ PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey();
+ String encodedMessage = Base64.encodeBase64String(message.getBytes());
+ String signedPayload;
+ try {
+ signedPayload = CommunicationUtils.signMessage(encodedMessage, devicePrivateKey);
+ } catch (TransportHandlerException e) {
+ String errorMsg = "Error occurred whilst trying to sign encrypted message of: [" + message + "]";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+
+ JSONObject jsonPayload = new JSONObject();
+ jsonPayload.put(JSON_MESSAGE_KEY, encodedMessage);
+ jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload);
+ //below statements are temporary fix.
+ jsonPayload.put(JSON_SERIAL_KEY, EnrollmentManager.getInstance().getSCEPCertificate().getSerialNumber());
+ return jsonPayload.toString();
+ } else {
+ return message;
+ }
+ }
+
+ public static String extractMessageFromPayload(String message) throws AgentCoreOperationException {
+ if (EnrollmentManager.getInstance().isEnrolled()) {
+ String actualMessage;
+
+ PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey();
+ JSONObject jsonPayload = new JSONObject(message);
+ Object encodedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
+ Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY);
+ boolean verification;
+
+ if (encodedMessage != null && signedPayload != null) {
+ try {
+ verification = CommunicationUtils.verifySignature(
+ encodedMessage.toString(), signedPayload.toString(), serverPublicKey);
+ } catch (TransportHandlerException e) {
+ String errorMsg =
+ "Error occurred whilst trying to verify signature on received message: [" + message + "]";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+ } else {
+ String errorMsg = "The received message is in an INVALID format. " +
+ "Need to be JSON - {\"Msg\":\"\", \"Sig\":\"\"}.";
+ throw new AgentCoreOperationException(errorMsg);
+ }
+ if (verification) {
+ actualMessage = new String(Base64.decodeBase64(encodedMessage.toString()), StandardCharsets.UTF_8);
+ } else {
+ String errorMsg = "Could not verify payload signature. The message was not signed by a valid client";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg);
+ }
+ return actualMessage;
+ } else {
+ return message;
+ }
+ }
+
+ public static String getAuthenticationMethod() {
+ String authMethod = "token";
+ switch (authMethod) {
+ case AgentConstants.TOKEN_AUTHENTICATION_METHOD:
+ return AgentConstants.TOKEN_AUTHENTICATION_METHOD;
+ default:
+ return "";
+ }
+ }
+
+ public static void refreshOAuthToken() throws AgentCoreOperationException {
+
+ AgentManager agentManager = AgentManager.getInstance();
+ String tokenEndpoint = agentManager.getAgentConfigs().getApimGatewayEndpoint();
+ tokenEndpoint = tokenEndpoint + APIManagerTokenUtils.TOKEN_ENDPOINT;
+
+ HttpURLConnection httpConnection = null;
+ BufferedReader connectionBuffer = null;
+ String requestPayload;
+ String dataFromBuffer;
+ StringBuilder responseMessage = new StringBuilder();
+
+ try {
+ String refreshToken = agentManager.getAgentConfigs().getRefreshToken();
+ String applicationScope = "device_type_" + AgentConstants.DEVICE_TYPE +
+ " device_" + agentManager.getAgentConfigs().getDeviceId();
+
+ requestPayload = APIManagerTokenUtils.GRANT_TYPE + "=" + APIManagerTokenUtils.REFRESH_TOKEN + "&" +
+ APIManagerTokenUtils.REFRESH_TOKEN + "=" + refreshToken + "&" +
+ APIManagerTokenUtils.SCOPE + "=" + applicationScope;
+
+ httpConnection = TransportUtils.getHttpConnection(tokenEndpoint);
+ httpConnection.setRequestMethod(AgentConstants.HTTP_POST);
+ httpConnection.setRequestProperty(AgentConstants.AUTHORIZATION_HEADER,
+ "Basic " + agentManager.getAgentConfigs().getApiApplicationKey());
+ httpConnection.setRequestProperty(AgentConstants.CONTENT_TYPE_HEADER, AgentConstants.X_WWW_FORM_URLENCODED);
+ httpConnection.setDoOutput(true);
+
+ DataOutputStream dataOutPutWriter = new DataOutputStream(httpConnection.getOutputStream());
+ dataOutPutWriter.writeBytes(requestPayload);
+ dataOutPutWriter.flush();
+ dataOutPutWriter.close();
+
+ log.info(AgentConstants.LOG_APPENDER + "Request to refresh OAuth token was sent to [" +
+ httpConnection.getURL() + "] with payload [" + requestPayload + "].");
+ log.info(AgentConstants.LOG_APPENDER + "Response [" + httpConnection.getResponseCode() + ":" +
+ httpConnection.getResponseMessage() + "] was received for token refresh attempt.");
+
+ if (httpConnection.getResponseCode() == HttpStatus.OK_200) {
+ connectionBuffer = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
+ while ((dataFromBuffer = connectionBuffer.readLine()) != null) {
+ responseMessage.append(dataFromBuffer);
+ }
+
+ log.info(AgentConstants.LOG_APPENDER +
+ "Response " + responseMessage + " was received for the token refresh call.");
+ updateExistingTokens(responseMessage.toString());
+ } else if (httpConnection.getResponseCode() == HttpStatus.BAD_REQUEST_400) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Token refresh call returned with a [400 Bad Request].\nThe refresh-token has " +
+ "probably expired.\nPlease contact System-Admin to get a valid refresh-token.");
+ } else {
+ log.warn(AgentConstants.LOG_APPENDER + "There was an issue with refreshing the Access Token.");
+ }
+
+ } catch (TransportHandlerException e) {
+ throw new AgentCoreOperationException(e);
+ } catch (ProtocolException e) {
+ String errorMsg = "Protocol specific error occurred when trying to set method to " +
+ AgentConstants.HTTP_POST + " for endpoint at: " + tokenEndpoint;
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+
+ } catch (IOException e) {
+ String errorMsg = "An IO error occurred whilst trying to get the response code from: " + tokenEndpoint +
+ " for a HTTP " + AgentConstants.HTTP_POST + " call.";
+ log.error(AgentConstants.LOG_APPENDER + errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } finally {
+ if (connectionBuffer != null) {
+ try {
+ connectionBuffer.close();
+ } catch (IOException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "Error encounter whilst attempting to close buffer to connection at: " +
+ tokenEndpoint);
+ }
+ }
+
+ if (httpConnection != null) {
+ httpConnection.disconnect();
+ }
+ }
+ }
+
+ private static void updateExistingTokens(String responseFromTokenEP) throws AgentCoreOperationException {
+ JSONObject jsonTokenObject = new JSONObject(responseFromTokenEP);
+ String newAccessToken = jsonTokenObject.get(APIManagerTokenUtils.ACCESS_TOKEN).toString();
+ String newRefreshToken = jsonTokenObject.get(APIManagerTokenUtils.REFRESH_TOKEN).toString();
+
+ if (newAccessToken == null || newRefreshToken == null) {
+ String msg =
+ "Neither Access-Token nor Refresh-Token was found in the response [" + responseFromTokenEP + "].";
+ log.error(AgentConstants.LOG_APPENDER + msg);
+ throw new AgentCoreOperationException(msg);
+ }
+
+ AgentManager.getInstance().getAgentConfigs().setAuthToken(newAccessToken);
+ AgentManager.getInstance().getAgentConfigs().setRefreshToken(newRefreshToken);
+ String deviceConfigFilePath =
+ AgentManager.getInstance().getRootPath() + AgentConstants.AGENT_PROPERTIES_FILE_NAME;
+
+ try {
+ PropertiesConfiguration propertyFileConfiguration = new PropertiesConfiguration(deviceConfigFilePath);
+ propertyFileConfiguration.setProperty(AgentConstants.AUTH_TOKEN_PROPERTY, newAccessToken);
+ propertyFileConfiguration.setProperty(AgentConstants.REFRESH_TOKEN_PROPERTY, newRefreshToken);
+ propertyFileConfiguration.save();
+ } catch (ConfigurationException e) {
+ String msg = "Error occurred whilst trying to update the [" + AgentConstants.AGENT_PROPERTIES_FILE_NAME +
+ "] at: " + deviceConfigFilePath + " will the new tokens.";
+ log.error(AgentConstants.LOG_APPENDER + msg);
+ throw new AgentCoreOperationException(msg);
+ }
+ }
+
+ private class APIManagerTokenUtils {
+ public static final String TOKEN_ENDPOINT = "/token";
+ public static final String GRANT_TYPE = "grant_type";
+ public static final String ACCESS_TOKEN = "access_token";
+ public static final String REFRESH_TOKEN = "refresh_token";
+ public static final String SCOPE = "scope";
+ }
+
+}
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java
new file mode 100644
index 000000000..26006620f
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.jscep.client.Client;
+import org.jscep.client.ClientException;
+import org.jscep.client.EnrollmentResponse;
+import org.jscep.client.verification.CertificateVerifier;
+import org.jscep.client.verification.OptimisticCertificateVerifier;
+import org.jscep.transaction.TransactionException;
+import org.jscep.transport.response.Capabilities;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException;
+import sun.security.x509.X509CertImpl;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * This class controls the entire SCEP enrolment process of the client. It is a singleton for any single client which
+ * has the agent code running in it. The main functionality of this class includes generating a Private-Public Key
+ * Pair for the enrollment flow, creating the Certificate-Sign-Request using the generated Public-Key to send to the
+ * SEP server, Contacting the SCEP server to receive the Signed Certificate and requesting for the server's public
+ * key for encrypting the payloads.
+ * The provider for all Cryptographic functions used in this class are "BouncyCastle" and the Asymmetric-Key pair
+ * algorithm used is "RSA" with a key size of 2048. The signature algorithm used is "SHA1withRSA".
+ * This class also holds the "SCEPUrl" (Server Url read from the configs file), the Private-Public Keys of the
+ * client, Signed SCEP certificate and the server's public certificate.
+ */
+
+//TODO: Need to save cert and keys to file after initial enrollment...
+public class EnrollmentManager {
+ private static final Log log = LogFactory.getLog(EnrollmentManager.class);
+ private static EnrollmentManager enrollmentManager;
+
+ private static final String KEY_PAIR_ALGORITHM = "RSA";
+ private static final String PROVIDER = "BC";
+ private static final String SIGNATURE_ALG = "SHA1withRSA";
+ private static final String CERT_IS_CA_EXTENSION = "is_ca";
+ private static final int KEY_SIZE = 2048;
+
+ // Seed to our PRNG. Make sure this is initialised randomly, NOT LIKE THIS
+ private static final byte[] SEED = ")(*&^%$#@!".getBytes();
+ private static final int CERT_VALIDITY = 730;
+
+ // URL of our SCEP server
+ private String SCEPUrl;
+ private PrivateKey privateKey;
+ private PublicKey publicKey;
+ private PublicKey serverPublicKey;
+ private X509Certificate SCEPCertificate;
+ private boolean isEnrolled = false;
+
+
+ /**
+ * Constructor of the EnrollmentManager. Initializes the SCEPUrl as read from the configuration file by the
+ * AgentManager.
+ */
+ private EnrollmentManager() {
+ this.SCEPUrl = AgentManager.getInstance().getEnrollmentEP();
+ //setEnrollmentStatus();
+ }
+
+ /**
+ * Method to return the current singleton instance of the EnrollmentManager.
+ *
+ * @return the current singleton instance if available and if not initializes a new instance and returns it.
+ */
+ public static EnrollmentManager getInstance() {
+ if (enrollmentManager == null) {
+ enrollmentManager = new EnrollmentManager();
+ }
+ return enrollmentManager;
+ }
+
+
+ public void setEnrollmentStatus() {
+ KeyStore keyStore;
+ try {
+ keyStore = KeyStore.getInstance(AgentConstants.DEVICE_KEYSTORE_TYPE);
+
+ this.isEnrolled = (keyStore.containsAlias(AgentConstants.DEVICE_CERT_ALIAS) &&
+ keyStore.containsAlias(AgentConstants.DEVICE_PRIVATE_KEY_ALIAS) &&
+ keyStore.containsAlias(AgentConstants.SERVER_CA_CERT_ALIAS));
+
+ } catch (KeyStoreException e) {
+ log.error(AgentConstants.LOG_APPENDER + "An error occurred whilst accessing the device KeyStore '" +
+ AgentConstants.DEVICE_KEYSTORE + "' with keystore type [" +
+ AgentConstants.DEVICE_KEYSTORE_TYPE + "] to ensure enrollment status.");
+ log.error(AgentConstants.LOG_APPENDER + e);
+ log.warn(AgentConstants.LOG_APPENDER + "Device will be re-enrolled.");
+ return;
+ }
+ try {
+ if (this.isEnrolled) {
+ this.SCEPCertificate = (X509Certificate) keyStore.getCertificate(AgentConstants.DEVICE_CERT_ALIAS);
+ this.privateKey = (PrivateKey) keyStore.getKey(AgentConstants.DEVICE_PRIVATE_KEY_ALIAS,
+ AgentConstants.DEVICE_KEYSTORE_PASSWORD.toCharArray());
+ this.publicKey = SCEPCertificate.getPublicKey();
+
+ X509Certificate serverCACert = (X509Certificate) keyStore.getCertificate(
+ AgentConstants.SERVER_CA_CERT_ALIAS);
+ this.serverPublicKey = serverCACert.getPublicKey();
+ log.info(AgentConstants.LOG_APPENDER +
+ "Device has already been enrolled. Hence, loaded certificate information from device" +
+ " trust-store.");
+ }
+ } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) {
+ log.error(AgentConstants.LOG_APPENDER + "An error occurred whilst accessing the device KeyStore '" +
+ AgentConstants.DEVICE_KEYSTORE + "' to ensure enrollment status.");
+ log.error(AgentConstants.LOG_APPENDER + e);
+ log.warn(AgentConstants.LOG_APPENDER + "Device will be re-enrolled.");
+ this.isEnrolled = false;
+ }
+ }
+
+ /**
+ * Method to control the entire enrollment flow. This method calls the method to create the Private-Public Key
+ * Pair, calls the specific method to generate the Certificate-Sign-Request, creates a one time self signed
+ * certificate to present to the SCEP server with the initial CSR, calls the specific method to connect to the
+ * SCEP Server and to get the SCEP Certificate and also calls the method that requests the SCEP Server for its
+ * PublicKey for future payload encryption.
+ *
+ * @throws AgentCoreOperationException if the private method generateCertSignRequest() fails with an error or if
+ * there is an error creating a self-sign certificate to present to the
+ * server (whilst trying to get the CSR signed)
+ */
+ public void beginEnrollmentFlow() throws AgentCoreOperationException {
+ Security.addProvider(new BouncyCastleProvider());
+
+ KeyPair keyPair = generateKeyPair();
+ this.privateKey = keyPair.getPrivate();
+ this.publicKey = keyPair.getPublic();
+
+ if (log.isDebugEnabled()) {
+ log.info(AgentConstants.LOG_APPENDER + "DevicePrivateKey:\n[\n" + privateKey + "\n]\n");
+ log.info(AgentConstants.LOG_APPENDER + "DevicePublicKey:\n[\n" + publicKey + "\n]\n");
+ }
+
+ PKCS10CertificationRequest certSignRequest = generateCertSignRequest();
+
+ /**
+ * -----------------------------------------------------------------------------------------------
+ * Generate an ephemeral self-signed certificate. This is needed to present to the CA in the SCEP request.
+ * In the future, add proper EKU and attributes in the request. The CA does NOT have to honour any of this.
+ * -----------------------------------------------------------------------------------------------
+ */
+ X500Name issuer = new X500Name("CN=Temporary Issuer");
+ BigInteger serial = new BigInteger(32, new SecureRandom());
+ Date fromDate = new Date();
+ Date toDate = new Date(System.currentTimeMillis() + (CERT_VALIDITY * 86400000L));
+
+ // Build the self-signed cert using BC, sign it with our private key (self-signed)
+ X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer, serial, fromDate, toDate,
+ certSignRequest.getSubject(),
+ certSignRequest.getSubjectPublicKeyInfo());
+ ContentSigner sigGen;
+ X509Certificate tmpCert;
+
+ try {
+ sigGen = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER).build(keyPair.getPrivate());
+ tmpCert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certBuilder.build(sigGen));
+ } catch (OperatorCreationException e) {
+ String errorMsg = "Error occurred whilst creating a ContentSigner for the Temp-Self-Signed Certificate.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } catch (CertificateException e) {
+ String errorMsg = "Error occurred whilst trying to create Temp-Self-Signed Certificate.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+ /**
+ * -----------------------------------------------------------------------------------------------
+ */
+
+ this.SCEPCertificate = getSignedCertificateFromServer(tmpCert, certSignRequest);
+ this.serverPublicKey = initPublicKeyOfServer();
+
+ storeCertificateToStore(AgentConstants.DEVICE_CERT_ALIAS, SCEPCertificate);
+ storeKeyToKeyStore(AgentConstants.DEVICE_PRIVATE_KEY_ALIAS, this.privateKey, SCEPCertificate);
+
+ if (log.isDebugEnabled()) {
+ log.info(AgentConstants.LOG_APPENDER +
+ "SCEPCertificate, DevicePrivateKey, ServerPublicKey was saved to device keystore [" +
+ AgentConstants.DEVICE_KEYSTORE + "]");
+ log.info(AgentConstants.LOG_APPENDER + "TemporaryCertPublicKey:\n[\n" + tmpCert.getPublicKey() + "\n]\n");
+ log.info(AgentConstants.LOG_APPENDER + "ServerPublicKey:\n[\n" + serverPublicKey + "\n]\n");
+ }
+ }
+
+ private void storeCertificateToStore(String alias, Certificate certificate) {
+ KeyStore keyStore;
+ try {
+ keyStore = KeyStore.getInstance(AgentConstants.DEVICE_KEYSTORE_TYPE);
+ keyStore.setCertificateEntry(alias, certificate);
+ keyStore.store(new FileOutputStream(AgentConstants.DEVICE_KEYSTORE),
+ AgentConstants.DEVICE_KEYSTORE_PASSWORD.toCharArray());
+
+ } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "An error occurred whilst trying to store the Certificate received from the SCEP " +
+ "Enrollment.");
+ log.error(AgentConstants.LOG_APPENDER + e);
+ log.warn(AgentConstants.LOG_APPENDER +
+ "SCEP Certificate was not stored in the keystore; " +
+ "Hence the device will be re-enrolled during next restart.");
+ }
+ }
+
+
+ private void storeKeyToKeyStore(String alias, Key cryptoKey, Certificate certInCertChain) {
+ KeyStore keyStore;
+ try {
+ keyStore = KeyStore.getInstance(AgentConstants.DEVICE_KEYSTORE_TYPE);
+ Certificate[] certChain = new Certificate[1];
+ certChain[0] = certInCertChain;
+
+ keyStore.setKeyEntry(alias, cryptoKey, AgentConstants.DEVICE_KEYSTORE_PASSWORD.toCharArray(), certChain);
+ keyStore.store(new FileOutputStream(AgentConstants.DEVICE_KEYSTORE),
+ AgentConstants.DEVICE_KEYSTORE_PASSWORD.toCharArray());
+
+ } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
+ log.error(AgentConstants.LOG_APPENDER +
+ "An error occurred whilst trying to store the key with alias " +
+ "[" + alias + "] in the device keystore.");
+ log.error(AgentConstants.LOG_APPENDER + e);
+ log.warn(AgentConstants.LOG_APPENDER +
+ "Key [" + alias + "] was not stored in the keystore; " +
+ "Hence the device will be re-enrolled during next restart.");
+ }
+ }
+
+ /**
+ * This method creates the Public-Private Key pair for the current client.
+ *
+ * @return the generated KeyPair object
+ * @throws AgentCoreOperationException when the given Security Provider does not exist or the Algorithmn used to
+ * generate the key pair is invalid.
+ */
+ private KeyPair generateKeyPair() throws AgentCoreOperationException {
+
+ // Generate key pair
+ KeyPairGenerator keyPairGenerator;
+ try {
+ keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM, PROVIDER);
+ keyPairGenerator.initialize(KEY_SIZE, new SecureRandom(SEED));
+ } catch (NoSuchAlgorithmException e) {
+ String errorMsg = "Algorithm [" + KEY_PAIR_ALGORITHM + "] provided for KeyPairGenerator is invalid.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } catch (NoSuchProviderException e) {
+ String errorMsg = "Provider [" + PROVIDER + "] provided for KeyPairGenerator does not exist.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+
+ return keyPairGenerator.genKeyPair();
+ }
+
+
+ /**
+ * This method creates the PKCS10 Certificate Sign Request which is to be sent to the SCEP Server using the
+ * generated PublicKey of the client. The certificate parameters used here are the ones from the AgentManager
+ * which are the values read from the configurations file.
+ *
+ * @return the PKCS10CertificationRequest object created using the client specific configs and the generated
+ * PublicKey
+ * @throws AgentCoreOperationException if an error occurs when creating a content signer to sign the CSR.
+ */
+ private PKCS10CertificationRequest generateCertSignRequest() throws AgentCoreOperationException {
+ // Build the CN for the cert that's being requested.
+ X500NameBuilder nameBld = new X500NameBuilder(BCStyle.INSTANCE);
+ nameBld.addRDN(BCStyle.CN, AgentManager.getInstance().getAgentConfigs().getTenantDomain());
+ nameBld.addRDN(BCStyle.O, AgentManager.getInstance().getAgentConfigs().getDeviceOwner());
+ nameBld.addRDN(BCStyle.OU, AgentManager.getInstance().getAgentConfigs().getDeviceOwner());
+ nameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, AgentManager.getInstance().getAgentConfigs().getDeviceId());
+ nameBld.addRDN(BCStyle.SERIALNUMBER, AgentManager.getInstance().getAgentConfigs().getDeviceId());
+ X500Name principal = nameBld.build();
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER);
+ ContentSigner contentSigner;
+
+ try {
+ contentSigner = contentSignerBuilder.build(this.privateKey);
+ } catch (OperatorCreationException e) {
+ String errorMsg = "Could not create content signer with private key.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+
+ // Generate the certificate signing request (csr = PKCS10)
+ PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(principal,
+ this.publicKey);
+ return reqBuilder.build(contentSigner);
+ }
+
+
+ /**
+ * This method connects to the SCEP Server to fetch the signed SCEP Certificate.
+ *
+ * @param tempCert the temporary self-signed certificate of the client required for the initial CSR
+ * request against the SCEP Server.
+ * @param certSignRequest the PKCS10 Certificate-Sign-Request that is to be sent to the SCEP Server.
+ * @return the SCEP-Certificate for the client signed by the SCEP-Server.
+ * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting
+ * the signed certificate fails or if the signed certificate cannot be
+ * retrieved from the reply from the server.
+ */
+ private X509Certificate getSignedCertificateFromServer(X509Certificate tempCert,
+ PKCS10CertificationRequest certSignRequest)
+ throws AgentCoreOperationException {
+
+ X509Certificate signedSCEPCertificate = null;
+ URL url;
+ EnrollmentResponse enrolResponse;
+ CertStore certStore;
+
+ try {
+ // The URL where we are going to request our cert from
+ url = new URL(this.SCEPUrl);
+
+ /* // This is called when we get the certificate for our CSR signed by CA
+ // Implement this handler to check the CA cert in prod. We can do cert pinning here
+ CallbackHandler cb = new CallbackHandler() {
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated
+ methods, choose Tools | Templates.
+ }
+ };*/
+
+ // Implement verification of the CA cert. VERIFY the CA
+ CertificateVerifier ocv = new OptimisticCertificateVerifier();
+
+ // Instantiate our SCEP client
+ Client scepClient = new Client(url, ocv);
+
+ // Submit our cert for signing. SCEP server should allow the client to specify
+ // the SCEP CA to issue the request against, if there are multiple CAs
+ enrolResponse = scepClient.enrol(tempCert, this.privateKey, certSignRequest);
+
+ // Verify we got what we want, and just print out the cert.
+ certStore = enrolResponse.getCertStore();
+
+ for (Certificate x509Certificate : certStore.getCertificates(null)) {
+ if (log.isDebugEnabled()) {
+ log.debug(x509Certificate.toString());
+ }
+ signedSCEPCertificate = (X509Certificate) x509Certificate;
+ }
+
+ } catch (MalformedURLException ex) {
+ String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl;
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, ex);
+ } catch (TransactionException | ClientException e) {
+ String errorMsg = "Enrollment process to SCEP Server at: " + SCEPUrl + " failed.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } catch (CertStoreException e) {
+ String errorMsg = "Could not retrieve [Signed-Certificate] from the response message from SCEP-Server.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+
+ return signedSCEPCertificate;
+ }
+
+
+ /**
+ * Gets the Public Key of the SCEP-Server and initializes it for later use. This method contacts the SCEP Server
+ * and fetches its CA Cert and extracts the Public Key of the server from the received reply.
+ *
+ * @return the public key of the SCEP Server which is to be used to encrypt pyloads.
+ * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting
+ * the signed certificate fails or if the signed certificate cannot be
+ * retrieved from the reply from the server.
+ */
+ private PublicKey initPublicKeyOfServer() throws AgentCoreOperationException {
+ URL url;
+ CertStore certStore;
+ PublicKey serverCertPublicKey = null;
+
+ try {
+ // The URL where we are going to request our cert from
+ url = new URL(this.SCEPUrl);
+
+ /* // This is called when we get the certificate for our CSR signed by CA
+ // Implement this handler to check the CA cert in prod. We can do cert pinning here
+ CallbackHandler cb = new CallbackHandler() {
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated
+ methods, choose Tools | Templates.
+ }
+ };*/
+
+ // Implement verification of the CA cert. VERIFY the CA
+ CertificateVerifier ocv = new OptimisticCertificateVerifier();
+
+ // Instantiate our SCEP client
+ Client scepClient = new Client(url, ocv);
+
+ // Get the CA capabilities. Should return SHA1withRSA for strongest hash and sig. Returns MD5.
+ if (log.isDebugEnabled()) {
+ Capabilities cap = scepClient.getCaCapabilities();
+ log.debug(String.format(
+ "\nStrongestCipher: %s,\nStrongestMessageDigest: %s,\nStrongestSignatureAlgorithm: %s," +
+ "\nIsRenewalSupported: %s,\nIsRolloverSupported: %s",
+ cap.getStrongestCipher(), cap.getStrongestMessageDigest(), cap.getStrongestSignatureAlgorithm(),
+ cap.isRenewalSupported(), cap.isRolloverSupported()));
+ }
+
+ certStore = scepClient.getCaCertificate();
+
+ for (Certificate cert : certStore.getCertificates(null)) {
+ if (cert instanceof X509Certificate) {
+ if (log.isDebugEnabled()) {
+ log.debug(((X509Certificate) cert).getIssuerDN().getName());
+ }
+
+ // I have chosen the CA cert based on its BasicConstraintExtension "is_ca" being set to "true"
+ // This is because the returned keystore may contain many certificates including RAs.
+ if (((Boolean) ((X509CertImpl) cert).getBasicConstraintsExtension().get(CERT_IS_CA_EXTENSION))) {
+ serverCertPublicKey = cert.getPublicKey();
+ storeCertificateToStore(AgentConstants.SERVER_CA_CERT_ALIAS, cert);
+ }
+ }
+ }
+
+ } catch (MalformedURLException ex) {
+ String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl;
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, ex);
+ } catch (ClientException e) {
+ String errorMsg = "Could not retrieve [Server-Certificate] from the SCEP-Server.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } catch (CertStoreException e) {
+ String errorMsg = "Could not retrieve [Server-Certificates] from the response message from SCEP-Server.";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ } catch (IOException e) {
+ String errorMsg = "Error occurred whilst trying to get property ['is_ca'] from the retreived Certificates";
+ log.error(errorMsg);
+ throw new AgentCoreOperationException(errorMsg, e);
+ }
+
+ return serverCertPublicKey;
+ }
+
+ /**
+ * Gets the Public-Key of the client.
+ *
+ * @return the public key of the client.
+ */
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ /**
+ * Gets the Private-Key of the client.
+ *
+ * @return the private key of the client.
+ */
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ /**
+ * Gets the SCEP-Certificate of the client.
+ *
+ * @return the SCEP Certificate of the client.
+ */
+ public X509Certificate getSCEPCertificate() {
+ return SCEPCertificate;
+ }
+
+ /**
+ * Gets the Public-Key of the Server.
+ *
+ * @return the pubic key of the server.
+ */
+ public PublicKey getServerPublicKey() {
+ return serverPublicKey;
+ }
+
+ /**
+ * Checks whether the device has already been enrolled with the SCEP Server.
+ *
+ * @return the enrollment status; 'TRUE' if already enrolled else 'FALSE'.
+ */
+ public boolean isEnrolled() {
+ return isEnrolled;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java
new file mode 100644
index 000000000..fac321ef9
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception;
+
+
+public class AgentCoreOperationException extends Exception{
+ private static final long serialVersionUID = 2736466230451105710L;
+
+ private String errorMessage;
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public AgentCoreOperationException(String msg, Exception nestedEx) {
+ super(msg, nestedEx);
+ setErrorMessage(msg);
+ }
+
+ public AgentCoreOperationException(String message, Throwable cause) {
+ super(message, cause);
+ setErrorMessage(message);
+ }
+
+ public AgentCoreOperationException(String msg) {
+ super(msg);
+ setErrorMessage(msg);
+ }
+
+ public AgentCoreOperationException() {
+ super();
+ }
+
+ public AgentCoreOperationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java
new file mode 100644
index 000000000..46a43a0ba
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+
+/**
+ * This is a utility class which contains methods common to the communication process of a client and the server. The
+ * methods include encryption/decryption of payloads and signing/verification of payloads received and to be sent.
+ */
+public class CommunicationUtils {
+ private static final Log log = LogFactory.getLog(TransportUtils.class);
+
+ // The Signature Algorithm used.
+ private static final String SHA_512 = "SHA-512";
+ // The Encryption Algorithm and the Padding used.
+ private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding";
+
+
+ /**
+ * Encrypts the message with the key that's passed in.
+ *
+ * @param message the message to be encrypted.
+ * @param encryptionKey the key to use for the encryption of the message.
+ * @return the encrypted message in String format.
+ * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding
+ * issues, encryption key being invalid or the algorithm used is unrecognizable.
+ */
+ public static String encryptMessage(String message, Key encryptionKey) throws TransportHandlerException {
+ Cipher encrypter;
+ byte[] cipherData;
+
+ try {
+ encrypter = Cipher.getInstance(CIPHER_PADDING);
+ encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey);
+ cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8));
+
+ } catch (NoSuchAlgorithmException e) {
+ String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (NoSuchPaddingException e) {
+ String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (InvalidKeyException e) {
+ String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (BadPaddingException e) {
+ String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (IllegalBlockSizeException e) {
+ String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ }
+
+ return Base64.encodeBase64String(cipherData);
+ }
+
+///TODO:: Exception needs to change according to the common package
+ /**
+ * Signed a given message using the PrivateKey that's passes in.
+ *
+ * @param message the message to be signed. Ideally some encrypted payload.
+ * @param signatureKey the PrivateKey with which the message is to be signed.
+ * @return the Base64Encoded String of the signed payload.
+ * @throws TransportHandlerException if some error occurs with the signing process which may be related to the
+ * signature algorithm used or the key used for signing.
+ */
+ public static String signMessage(String message, PrivateKey signatureKey) throws TransportHandlerException {
+
+ Signature signature;
+ String signedEncodedString;
+
+ try {
+ signature = Signature.getInstance(SHA_512);
+ signature.initSign(signatureKey);
+ signature.update(Base64.decodeBase64(message));
+
+ byte[] signatureBytes = signature.sign();
+ signedEncodedString = Base64.encodeBase64String(signatureBytes);
+
+ } catch (NoSuchAlgorithmException e) {
+ String errorMsg =
+ "Algorithm not found exception occurred for Signature instance of [" + SHA_512 + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (SignatureException e) {
+ String errorMsg = "Signature exception occurred for Signature instance of [" + SHA_512 + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (InvalidKeyException e) {
+ String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ }
+
+ return signedEncodedString;
+ }
+
+
+ /**
+ * Verifies some signed-data against the a Public-Key to ensure that it was produced by the holder of the
+ * corresponding Private Key.
+ *
+ * @param data the actual payoad which was signed by some Private Key.
+ * @param signedData the signed data produced by signing the payload using a Private Key.
+ * @param verificationKey the corresponding Public Key which is an exact pair of the Private-Key with we expect
+ * the data to be signed by.
+ * @return true if the signed data verifies to be signed by the corresponding Private Key.
+ * @throws TransportHandlerException if some error occurs with the verification process which may be related to
+ * the signature algorithm used or the key used for signing.
+ */
+ public static boolean verifySignature(String data, String signedData, PublicKey verificationKey)
+ throws TransportHandlerException {
+
+ Signature signature;
+ boolean verified;
+
+ try {
+ signature = Signature.getInstance(SHA_512);
+ signature.initVerify(verificationKey);
+ signature.update(Base64.decodeBase64(data));
+
+ verified = signature.verify(Base64.decodeBase64(signedData));
+
+ } catch (NoSuchAlgorithmException e) {
+ String errorMsg =
+ "Algorithm not found exception occurred for Signature instance of [" + SHA_512 + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (SignatureException e) {
+ String errorMsg = "Signature exception occurred for Signature instance of [" + SHA_512 + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (InvalidKeyException e) {
+ String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ }
+
+ return verified;
+ }
+
+
+ /**
+ * Encrypts the message with the key that's passed in.
+ *
+ * @param encryptedMessage the encrypted message that is supposed to be decrypted.
+ * @param decryptKey the key to use in the decryption process.
+ * @return the decrypted message in String format.
+ * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding
+ * issues, encryption key being invalid or the algorithm used is unrecognizable.
+ */
+ public static String decryptMessage(String encryptedMessage, Key decryptKey) throws TransportHandlerException {
+
+ Cipher decrypter;
+ String decryptedMessage;
+
+ try {
+
+ decrypter = Cipher.getInstance(CIPHER_PADDING);
+ decrypter.init(Cipher.DECRYPT_MODE, decryptKey);
+ decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)),
+ StandardCharsets.UTF_8);
+
+ } catch (NoSuchAlgorithmException e) {
+ String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (NoSuchPaddingException e) {
+ String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (InvalidKeyException e) {
+ String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (BadPaddingException e) {
+ String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (IllegalBlockSizeException e) {
+ String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ }
+
+ return decryptedMessage;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java
new file mode 100644
index 000000000..fa45cdbb0
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport;
+
+/**
+ * This interface consists of the core functionality related to the transport between any device and the server. The
+ * interface is an abstraction, regardless of the underlying protocol used for the transport. Implementation of this
+ * interface by any class that caters a specific protocol (ex: HTTP, XMPP, MQTT, CoAP) would ideally have methods
+ * specific to the protocol used for communication and thees methods that implement the logic related to the devices
+ * using the protocol.
+ *
+ * @param a message type specific to the protocol implemented
+ */
+public interface TransportHandler {
+ int DEFAULT_TIMEOUT_INTERVAL = 5000; // millis ~ 10 sec
+
+ void connect();
+
+ boolean isConnected();
+
+ //TODO:: Any errors needs to be thrown ahead
+ void processIncomingMessage(T message, String... messageParams);
+
+ void processIncomingMessage();
+
+ void publishDeviceData(String... publishData);
+
+ void publishDeviceData();
+
+ void disconnect();
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java
new file mode 100644
index 000000000..9ae69a998
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport;
+
+public class TransportHandlerException extends Exception {
+ private static final long serialVersionUID = 2736466230451105440L;
+
+ private String errorMessage;
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public TransportHandlerException(String msg, Exception nestedEx) {
+ super(msg, nestedEx);
+ setErrorMessage(msg);
+ }
+
+ public TransportHandlerException(String message, Throwable cause) {
+ super(message, cause);
+ setErrorMessage(message);
+ }
+
+ public TransportHandlerException(String msg) {
+ super(msg);
+ setErrorMessage(msg);
+ }
+
+ public TransportHandlerException() {
+ super();
+ }
+
+ public TransportHandlerException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java
new file mode 100644
index 000000000..b55aee02d
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.DatagramSocket;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+public class TransportUtils {
+ private static final Log log = LogFactory.getLog(TransportUtils.class);
+
+ public static final int MIN_PORT_NUMBER = 9000;
+ public static final int MAX_PORT_NUMBER = 11000;
+
+ /**
+ * Given a server endpoint as a String, this method splits it into Protocol, Host and Port
+ *
+ * @param ipString a network endpoint in the format - '://:'
+ * @return a map with keys "Protocol", "Host" & "Port" for the related values from the ipString
+ * @throws TransportHandlerException
+ */
+ public static Map getHostAndPort(String ipString)
+ throws TransportHandlerException {
+ Map ipPortMap = new HashMap();
+ String[] ipPortArray = ipString.split(":");
+
+ if (ipPortArray.length != 3) {
+ String errorMsg =
+ "The IP String - '" + ipString +
+ "' is invalid. It needs to be in format '://:'.";
+ log.info(errorMsg);
+ throw new TransportHandlerException(errorMsg);
+ }
+
+ ipPortMap.put(AgentConstants.PROTOCOL_PROPERTY, ipPortArray[0]);
+ ipPortMap.put(AgentConstants.HOST_PROPERTY, ipPortArray[1].replace("/", ""));
+ ipPortMap.put(AgentConstants.PORT_PROPERTY, ipPortArray[2]);
+ return ipPortMap;
+ }
+
+ /**
+ * This method validates whether a specific IP Address is of IPv4 type
+ *
+ * @param ipAddress the IP Address which needs to be validated
+ * @return true if it is of IPv4 type and false otherwise
+ */
+ public static boolean validateIPv4(String ipAddress) {
+ try {
+ if (ipAddress == null || ipAddress.isEmpty()) {
+ return false;
+ }
+
+ String[] parts = ipAddress.split("\\.");
+ if (parts.length != 4) {
+ return false;
+ }
+
+ for (String s : parts) {
+ int i = Integer.parseInt(s);
+ if ((i < 0) || (i > 255)) {
+ return false;
+ }
+ }
+ return !ipAddress.endsWith(".");
+
+ } catch (NumberFormatException nfe) {
+ log.warn("The IP Address: " + ipAddress + " could not be validated against IPv4-style");
+ return false;
+ }
+ }
+
+
+ public static Map getInterfaceIPMap() throws TransportHandlerException {
+
+ Map interfaceToIPMap = new HashMap();
+ Enumeration networkInterfaces;
+ String networkInterfaceName = "";
+ String ipAddress;
+
+ try {
+ networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ } catch (SocketException exception) {
+ String errorMsg =
+ "Error encountered whilst trying to get the list of network-interfaces";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, exception);
+ }
+
+ try {
+ for (; networkInterfaces.hasMoreElements(); ) {
+ networkInterfaceName = networkInterfaces.nextElement().getName();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Network Interface: " + networkInterfaceName);
+ log.debug("------------------------------------------");
+ }
+
+ Enumeration interfaceIPAddresses = NetworkInterface.getByName(
+ networkInterfaceName).getInetAddresses();
+
+ for (; interfaceIPAddresses.hasMoreElements(); ) {
+ ipAddress = interfaceIPAddresses.nextElement().getHostAddress();
+
+ if (log.isDebugEnabled()) {
+ log.debug("IP Address: " + ipAddress);
+ }
+
+ if (TransportUtils.validateIPv4(ipAddress)) {
+ interfaceToIPMap.put(networkInterfaceName, ipAddress);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("------------------------------------------");
+ }
+ }
+ } catch (SocketException exception) {
+ String errorMsg =
+ "Error encountered whilst trying to get the IP Addresses of the network " +
+ "interface: " + networkInterfaceName;
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, exception);
+ }
+
+ return interfaceToIPMap;
+ }
+
+
+ /**
+ * Attempts to find a free port between the MIN_PORT_NUMBER(9000) and MAX_PORT_NUMBER(11000).
+ * Tries 'RANDOMLY picked' port numbers between this range up-until "randomAttempts" number of
+ * times. If still fails, then tries each port in descending order from the MAX_PORT_NUMBER
+ * whilst skipping already attempted ones via random selection.
+ *
+ * @param randomAttempts no of times to TEST port numbers picked randomly over the given range
+ * @return an available/free port
+ */
+ public static synchronized int getAvailablePort(int randomAttempts) {
+ ArrayList failedPorts = new ArrayList(randomAttempts);
+ try {
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ int randomPort = MAX_PORT_NUMBER;
+ while (randomAttempts > 0) {
+ randomPort = secureRandom.nextInt(MAX_PORT_NUMBER - MIN_PORT_NUMBER) + MIN_PORT_NUMBER;
+ if (checkIfPortAvailable(randomPort)) {
+ return randomPort;
+ }
+ failedPorts.add(randomPort);
+ randomAttempts--;
+ }
+ randomPort = MAX_PORT_NUMBER;
+ while (true) {
+ if (!failedPorts.contains(randomPort) && checkIfPortAvailable(randomPort)) {
+ return randomPort;
+ }
+ randomPort--;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA1PRNG algorithm could not be found.");
+ }
+ }
+
+
+ private static boolean checkIfPortAvailable(int port) {
+ ServerSocket tcpSocket = null;
+ DatagramSocket udpSocket = null;
+
+ try {
+ tcpSocket = new ServerSocket(port);
+ tcpSocket.setReuseAddress(true);
+
+ udpSocket = new DatagramSocket(port);
+ udpSocket.setReuseAddress(true);
+ return true;
+ } catch (IOException ex) {
+ // denotes the port is in use
+ } finally {
+ if (tcpSocket != null) {
+ try {
+ tcpSocket.close();
+ } catch (IOException e) {
+ /* not to be thrown */
+ }
+ }
+
+ if (udpSocket != null) {
+ udpSocket.close();
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * This is a utility method that creates and returns a HTTP connection object.
+ *
+ * @param urlString the URL pattern to which the connection needs to be created
+ * @return an HTTPConnection object which cn be used to send HTTP requests
+ * @throws TransportHandlerException if errors occur when creating the HTTP connection with
+ * the given URL string
+ */
+ public static HttpURLConnection getHttpConnection(String urlString) throws
+ TransportHandlerException {
+ URL connectionUrl;
+ HttpURLConnection httpConnection;
+
+ try {
+ connectionUrl = new URL(urlString);
+ httpConnection = (HttpURLConnection) connectionUrl.openConnection();
+ } catch (MalformedURLException e) {
+ String errorMsg = "Error occured whilst trying to form HTTP-URL from string: " + urlString;
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, e);
+ } catch (IOException exception) {
+ String errorMsg = "Error occured whilst trying to open a connection to: " + urlString;
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, exception);
+ }
+ return httpConnection;
+ }
+
+ /**
+ * This is a utility method that reads and returns the response from a HTTP connection
+ *
+ * @param httpConnection the connection from which a response is expected
+ * @return the response (as a string) from the given HTTP connection
+ * @throws TransportHandlerException if any errors occur whilst reading the response from
+ * the connection stream
+ */
+ public static String readResponseFromHttpRequest(HttpURLConnection httpConnection)
+ throws TransportHandlerException {
+ BufferedReader bufferedReader;
+ try {
+ bufferedReader = new BufferedReader(new InputStreamReader(
+ httpConnection.getInputStream(), StandardCharsets.UTF_8));
+ } catch (IOException exception) {
+ String errorMsg = "There is an issue with connecting the reader to the input stream at: " +
+ httpConnection.getURL();
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, exception);
+ }
+
+ String responseLine;
+ StringBuilder completeResponse = new StringBuilder();
+
+ try {
+ while ((responseLine = bufferedReader.readLine()) != null) {
+ completeResponse.append(responseLine);
+ }
+ } catch (IOException exception) {
+ String errorMsg = "Error occured whilst trying read from the connection stream at: " +
+ httpConnection.getURL();
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, exception);
+ }
+ try {
+ bufferedReader.close();
+ } catch (IOException exception) {
+ log.error("Could not succesfully close the bufferedReader to the connection at: " + httpConnection.getURL());
+ }
+ return completeResponse.toString();
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java
new file mode 100644
index 000000000..c771eb8ed
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.http;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.jetty.server.Server;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils;
+
+/**
+ * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for
+ * the core functionality with regards to device-server communication regardless of the Transport protocol. This
+ * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the
+ * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler"
+ * interface, does not contain the logic relevant to the interface methods. The specific functionality of the
+ * interface methods are intended to be implemented by the concrete class that extends this abstract class and
+ * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device
+ * via HTTP Protocol).
+ */
+public abstract class HTTPTransportHandler implements TransportHandler {
+ private static final Log log = LogFactory.getLog(HTTPTransportHandler.class);
+
+ protected Server server;
+ protected int port;
+ protected int timeoutInterval;
+
+ protected HTTPTransportHandler() {
+ this.port = TransportUtils.getAvailablePort(10);
+ this.server = new Server(port);
+ timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
+ }
+
+ protected HTTPTransportHandler(int port) {
+ this.port = port;
+ this.server = new Server(this.port);
+ timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
+ }
+
+ protected HTTPTransportHandler(int port, int timeoutInterval) {
+ this.port = port;
+ this.server = new Server(this.port);
+ this.timeoutInterval = timeoutInterval;
+ }
+
+ public void setTimeoutInterval(int timeoutInterval) {
+ this.timeoutInterval = timeoutInterval;
+ }
+
+ /**
+ * Checks whether the HTTP server is up and listening for incoming requests.
+ *
+ * @return true if the server is up & listening for requests, else false.
+ */
+ public boolean isConnected() {
+ return server.isStarted();
+ }
+
+
+ protected void incrementPort() {
+ this.port = this.port + 1;
+ server = new Server(port);
+ }
+
+ /**
+ * Shuts-down the HTTP Server.
+ */
+ public void closeConnection() throws Exception {
+ if (server != null && isConnected()) {
+ server.stop();
+ }
+ }
+
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java
new file mode 100644
index 000000000..f7c6864c1
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.mqtt;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttSecurityException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for
+ * the core functionality with regards to device-server communication regardless of the Transport protocol. This
+ * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the
+ * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler"
+ * interface, does not contain the logic relevant to the interface methods. The specific functionality of the
+ * interface methods are intended to be implemented by the concrete class that extends this abstract class and
+ * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device
+ * via HTTP Protocol).
+ *
+ * This class contains the Device-Management specific implementation for all the MQTT functionality. This includes
+ * connecting to a MQTT Broker & subscribing to the appropriate MQTT-topic, action plan upon losing connection or
+ * successfully delivering a message to the broker and processing incoming messages. Makes use of the 'Paho-MQTT'
+ * library provided by Eclipse Org.
+ */
+public abstract class MQTTTransportHandler
+ implements MqttCallback, TransportHandler {
+ private static final Log log = LogFactory.getLog(MQTTTransportHandler.class);
+ public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
+
+ private MqttClient client;
+ private String clientId;
+ private MqttConnectOptions options;
+ private String clientWillTopic;
+
+ protected String mqttBrokerEndPoint;
+ protected int timeoutInterval;
+ protected String subscribeTopic;
+
+ /**
+ * Constructor for the MQTTTransportHandler which takes in the owner, type of the device
+ * and the MQTT Broker URL and the topic to subscribe.
+ *
+ * @param deviceOwner the owner of the device.
+ * @param deviceType the CDMF Device-Type of the device.
+ * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint.
+ * @param subscribeTopic the MQTT topic to which the client is to be subscribed
+ */
+ protected MQTTTransportHandler(String deviceOwner, String deviceType,
+ String mqttBrokerEndPoint,
+ String subscribeTopic) {
+ this.clientId = deviceOwner + ":" + deviceType;
+ this.subscribeTopic = subscribeTopic;
+ this.clientWillTopic = deviceType + File.separator + "disconnection";
+ this.mqttBrokerEndPoint = mqttBrokerEndPoint;
+ this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
+ this.initSubscriber();
+ }
+
+ /**
+ * Constructor for the MQTTTransportHandler which takes in the owner, type of the device
+ * and the MQTT Broker URL and the topic to subscribe. Additionally this constructor takes in
+ * the reconnection-time interval between successive attempts to connect to the broker.
+ *
+ * @param deviceOwner the owner of the device.
+ * @param deviceType the CDMF Device-Type of the device.
+ * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint.
+ * @param subscribeTopic the MQTT topic to which the client is to be subscribed
+ * @param intervalInMillis the time interval in MILLI-SECONDS between successive
+ * attempts to connect to the broker.
+ */
+ protected MQTTTransportHandler(String deviceOwner, String deviceType,
+ String mqttBrokerEndPoint, String subscribeTopic,
+ int intervalInMillis) {
+ this.clientId = deviceOwner + ":" + deviceType;
+ this.subscribeTopic = subscribeTopic;
+ //TODO:: Use constant strings
+ this.clientWillTopic = deviceType + File.separator + "disconnection";
+ this.mqttBrokerEndPoint = mqttBrokerEndPoint;
+ this.timeoutInterval = intervalInMillis;
+ this.initSubscriber();
+ }
+
+ public void setTimeoutInterval(int timeoutInterval) {
+ this.timeoutInterval = timeoutInterval;
+ }
+
+ /**
+ * Initializes the MQTT-Client. Creates a client using the given MQTT-broker endpoint and the
+ * clientId (which is constructed by a concatenation of [deviceOwner]:[deviceType]). Also sets
+ * the client's options parameter with the clientWillTopic (in-case of connection failure) and
+ * other info. Also sets the call-back this current class.
+ */
+ private void initSubscriber() {
+ try {
+ client = new MqttClient(this.mqttBrokerEndPoint, clientId, null);
+ //TODO:: Need to check for debug
+ log.info("MQTT subscriber was created with ClientID : " + clientId);
+ } catch (MqttException ex) {
+ //TODO:: Remove unnecessary formatting and print exception
+ String errorMsg = "MQTT Client Error\n" + "\tReason: " + ex.getReasonCode() +
+ "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " +
+ ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() +
+ "\n\tException: " + ex;
+ log.error(errorMsg);
+ //TODO:: Throw the error out
+ }
+
+ options = new MqttConnectOptions();
+ options.setCleanSession(false);
+ //TODO:: Use constant strings
+ options.setWill(clientWillTopic, "Connection-Lost".getBytes(StandardCharsets.UTF_8), 2,
+ true);
+ client.setCallback(this);
+ }
+
+ /**
+ * Checks whether the connection to the MQTT-Broker persists.
+ *
+ * @return true if the client is connected to the MQTT-Broker, else false.
+ */
+ @Override
+ public boolean isConnected() {
+ return client.isConnected();
+ }
+
+
+ protected void connectToQueue(String username, String password) throws TransportHandlerException {
+ options.setUserName(username);
+ options.setPassword(password.toCharArray());
+ connectToQueue();
+ }
+
+ /**
+ * Connects to the MQTT-Broker and if successfully established connection.
+ *
+ * @throws TransportHandlerException in the event of 'Connecting to' the MQTT broker fails.
+ */
+ protected void connectToQueue() throws TransportHandlerException {
+ try {
+ client.connect(options);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Subscriber connected to queue at: " + this.mqttBrokerEndPoint);
+ }
+ } catch (MqttSecurityException ex) {
+ String errorMsg = "MQTT Security Exception when connecting to queue\n" + "\tReason: " +
+ " " +
+ ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() +
+ "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " +
+ ex.getCause() + "\n\tException: " + ex;
+ //TODO:: Compulsory log of errors and remove formatted error
+ if (log.isDebugEnabled()) {
+ log.debug(errorMsg);
+ }
+ throw new TransportHandlerException(errorMsg, ex);
+
+ } catch (MqttException ex) {
+ //TODO:: Compulsory log of errors and remove formatted error
+ String errorMsg = "MQTT Exception when connecting to queue\n" + "\tReason: " +
+ ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() +
+ "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " +
+ ex.getCause() + "\n\tException: " + ex;
+ if (log.isDebugEnabled()) {
+ log.debug(errorMsg);
+ }
+ throw new TransportHandlerException(errorMsg, ex);
+ }
+ }
+
+ /**
+ * Subscribes to the MQTT-Topic specific to this MQTT Client. (The MQTT-Topic specific to the
+ * device is taken in as a constructor parameter of this class) .
+ *
+ * @throws TransportHandlerException in the event of 'Subscribing to' the MQTT broker
+ * fails.
+ */
+ protected void subscribeToQueue() throws TransportHandlerException {
+ try {
+ //TODO:: QoS Level take it from a variable
+ client.subscribe(subscribeTopic, 0);
+ log.info("Subscriber '" + clientId + "' subscribed to topic: " + subscribeTopic);
+ } catch (MqttException ex) {
+ //TODO:: Compulsory log of errors and remove formatted error
+ String errorMsg = "MQTT Exception when trying to subscribe to topic: " +
+ subscribeTopic + "\n\tReason: " + ex.getReasonCode() +
+ "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " +
+ ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() +
+ "\n\tException: " + ex;
+ if (log.isDebugEnabled()) {
+ log.debug(errorMsg);
+ }
+
+ throw new TransportHandlerException(errorMsg, ex);
+ }
+ }
+
+
+ /**
+ * This method is used to publish reply-messages for the control signals received.
+ * Invocation of this method calls its overloaded-method with a QoS equal to that of the
+ * default value.
+ *
+ * @param topic the topic to which the reply message is to be published.
+ * @param payLoad the reply-message (payload) of the MQTT publish action.
+ */
+ protected void publishToQueue(String topic, String payLoad)
+ throws TransportHandlerException {
+ publishToQueue(topic, payLoad, DEFAULT_MQTT_QUALITY_OF_SERVICE, false);
+ }
+
+ /**
+ * This is an overloaded method that publishes MQTT reply-messages for control signals
+ * received form the IoT-Server.
+ *
+ * @param topic the topic to which the reply message is to be published
+ * @param payLoad the reply-message (payload) of the MQTT publish action.
+ * @param qos the Quality-of-Service of the current publish action.
+ * Could be 0(At-most once), 1(At-least once) or 2(Exactly once)
+ */
+ protected void publishToQueue(String topic, String payLoad, int qos, boolean retained)
+ throws TransportHandlerException {
+ try {
+ client.publish(topic, payLoad.getBytes(StandardCharsets.UTF_8), qos, retained);
+ if (log.isDebugEnabled()) {
+ log.debug("Message: " + payLoad + " to MQTT topic [" + topic + "] published successfully");
+ }
+ } catch (MqttException ex) {
+ String errorMsg =
+ "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " +
+ ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() +
+ "\n\tCause: " + ex.getCause() + "\n\tException: " + ex;
+ log.info(errorMsg);
+ throw new TransportHandlerException(errorMsg, ex);
+ }
+ }
+
+
+ protected void publishToQueue(String topic, MqttMessage message)
+ throws TransportHandlerException {
+ try {
+ client.publish(topic, message);
+ if (log.isDebugEnabled()) {
+ log.debug("Message: " + message.toString() + " to MQTT topic [" + topic + "] published successfully");
+ }
+ } catch (MqttException ex) {
+ //TODO:: Compulsory log of errors and remove formatted error
+ String errorMsg =
+ "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " +
+ ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() +
+ "\n\tCause: " + ex.getCause() + "\n\tException: " + ex;
+ log.info(errorMsg);
+ throw new TransportHandlerException(errorMsg, ex);
+ }
+ }
+
+
+ /**
+ * Callback method which is triggered once the MQTT client losers its connection to the broker.
+ * Spawns a new thread that executes necessary actions to try and reconnect to the endpoint.
+ *
+ * @param throwable a Throwable Object containing the details as to why the failure occurred.
+ */
+ @Override
+ public void connectionLost(Throwable throwable) {
+ log.warn("Lost Connection for client: " + this.clientId +
+ " to " + this.mqttBrokerEndPoint + ".\nThis was due to - " + throwable.getMessage());
+
+ Thread reconnectThread = new Thread() {
+ public void run() {
+ connect();
+ }
+ };
+ reconnectThread.start();
+ }
+
+ /**
+ * Callback method which is triggered upon receiving a MQTT Message from the broker. Spawns a
+ * new thread that executes any actions to be taken with the received message.
+ *
+ * @param topic the MQTT-Topic to which the received message was published to and the
+ * client was subscribed to.
+ * @param mqttMessage the actual MQTT-Message that was received from the broker.
+ */
+ @Override
+ public void messageArrived(final String topic, final MqttMessage mqttMessage) {
+ if (log.isDebugEnabled()) {
+ log.info("Got an MQTT message '" + mqttMessage.toString() + "' for topic '" + topic + "'.");
+ }
+
+ Thread messageProcessorThread = new Thread() {
+ public void run() {
+ processIncomingMessage(mqttMessage, topic);
+ }
+ };
+ messageProcessorThread.setDaemon(true);
+ messageProcessorThread.start();
+ }
+
+ /**
+ * Callback method which gets triggered upon successful completion of a message delivery to
+ * the broker.
+ *
+ * @param iMqttDeliveryToken the MQTT-DeliveryToken which includes the details about the
+ * specific message delivery.
+ */
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+ String message = "";
+ try {
+ message = iMqttDeliveryToken.getMessage().toString();
+ } catch (MqttException e) {
+ //TODO:: Throw errors
+ log.error(
+ "Error occurred whilst trying to read the message from the MQTT delivery token.");
+ }
+ String topic = iMqttDeliveryToken.getTopics()[0];
+ String client = iMqttDeliveryToken.getClient().getClientId();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Message - '" + message + "' of client [" + client + "] for the topic (" +
+ topic + ") was delivered successfully.");
+ }
+ }
+
+ /**
+ * Closes the connection to the MQTT Broker.
+ */
+ public void closeConnection() throws MqttException {
+ if (client != null && isConnected()) {
+ client.disconnect();
+ }
+ }
+}
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java
new file mode 100644
index 000000000..4ac76f45b
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.xmpp;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.FromContainsFilter;
+import org.jivesoftware.smack.filter.OrFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.filter.ToContainsFilter;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
+
+/**
+ * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for
+ * the core functionality with regards to device-server communication regardless of the Transport protocol. This
+ * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the
+ * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler"
+ * interface, does not contain the logic relevant to the interface methods. The specific functionality of the
+ * interface methods are intended to be implemented by the concrete class that extends this abstract class and
+ * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device
+ * via HTTP Protocol).
+ *
+ * This class contains the IoT-Server specific implementation for all the XMPP functionality. This includes
+ * connecting to a XMPP Server & Login-In using the device's/server's XMPP-Account, Setting listeners and filters on
+ * incoming XMPP messages and Sending XMPP replies for messages received. Makes use of the 'Smack-XMPP' library
+ * provided by jivesoftware/igniterealtime.
+ */
+public abstract class XMPPTransportHandler implements TransportHandler {
+ private static final Log log = LogFactory.getLog(XMPPTransportHandler.class);
+
+ protected String server;
+ protected int timeoutInterval; // millis
+
+ //TODO:: Shouldnt be hard-coded. Need to be read from configs
+ private static final int DEFAULT_XMPP_PORT = 5222;
+ private XMPPConnection connection;
+ private int port;
+ private ConnectionConfiguration config;
+ private PacketFilter filter;
+ private PacketListener listener;
+
+
+ /**
+ * Constructor for XMPPTransportHandler passing only the server-IP.
+ *
+ * @param server the IP of the XMPP server.
+ */
+ protected XMPPTransportHandler(String server) {
+ this.server = server;
+ this.port = DEFAULT_XMPP_PORT;
+ this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
+ initXMPPClient();
+ }
+
+ /**
+ * Constructor for XMPPTransportHandler passing server-IP and the XMPP-port.
+ *
+ * @param server the IP of the XMPP server.
+ * @param port the XMPP server's port to connect to. (default - 5222)
+ */
+ protected XMPPTransportHandler(String server, int port) {
+ this.server = server;
+ this.port = port;
+ this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
+ initXMPPClient();
+ }
+
+ /**
+ * Constructor for XMPPTransportHandler passing server-IP, the XMPP-port and the
+ * timeoutInterval used by listeners to the server and for reconnection schedules.
+ *
+ * @param server the IP of the XMPP server.
+ * @param port the XMPP server's port to connect to. (default - 5222)
+ * @param timeoutInterval the timeout interval to use for the connection and reconnection
+ */
+ protected XMPPTransportHandler(String server, int port, int timeoutInterval) {
+ this.server = server;
+ this.port = port;
+ this.timeoutInterval = timeoutInterval;
+ initXMPPClient();
+ }
+
+ /**
+ * Sets the client's time-out-limit whilst waiting for XMPP-replies from server.
+ *
+ * @param millis the time in millis to be set as the time-out-limit whilst waiting for a
+ * XMPP-reply.
+ */
+ public void setTimeoutInterval(int millis) {
+ this.timeoutInterval = millis;
+ }
+
+ /**
+ * Checks whether the connection to the XMPP-Server persists.
+ *
+ * @return true if the client is connected to the XMPP-Server, else false.
+ */
+ @Override
+ public boolean isConnected() {
+ return connection.isConnected();
+ }
+
+ /**
+ * Initializes the XMPP Client. Sets the time-out-limit whilst waiting for XMPP-replies from
+ * server. Sets the XMPP configurations to connect to the server and creates the
+ * XMPPConnection object used for connecting and Logging-In.
+ */
+ private void initXMPPClient() {
+ log.info(String.format("Initializing connection to XMPP Server at %1$s via port " +
+ "%2$d.", server, port));
+ SmackConfiguration.setPacketReplyTimeout(timeoutInterval);
+ config = new ConnectionConfiguration(server, port);
+// TODO:: Need to enable SASL-Authentication appropriately
+ config.setSASLAuthenticationEnabled(false);
+ config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
+ connection = new XMPPConnection(config);
+ }
+
+//TODO:: Re-check all exception handling
+
+ /**
+ * Connects to the XMPP-Server and if attempt unsuccessful, then throws exception.
+ *
+ * @throws TransportHandlerException in the event of 'Connecting to' the XMPP server fails.
+ */
+ protected void connectToServer() throws TransportHandlerException {
+ try {
+ connection.connect();
+ log.info(String.format("Connection to XMPP Server at %1$s established successfully......", server));
+
+ } catch (XMPPException xmppExcepion) {
+ String errorMsg = "Connection attempt to the XMPP Server at " + server + " via port " + port + " failed.";
+ log.info(errorMsg);
+ throw new TransportHandlerException(errorMsg, xmppExcepion);
+ }
+ }
+
+ /**
+ * If successfully established connection, then tries to Log in using the device's XMPP
+ * Account credentials.
+ *
+ * @param username the username of the device's XMPP-Account.
+ * @param password the password of the device's XMPP-Account.
+ * @param resource the resource the resource, specific to the XMPP-Account to which the login
+ * is made to
+ * @throws TransportHandlerException in the event of 'Logging into' the XMPP server fails.
+ */
+ protected void loginToServer(String username, String password, String resource)
+ throws TransportHandlerException {
+ if (isConnected()) {
+ try {
+ if (resource == null) {
+ connection.login(username, password);
+ log.info(String.format("Logged into XMPP Server at %1$s as user %2$s......", server, username));
+ } else {
+ connection.login(username, password, resource);
+ log.info(String.format("Logged into XMPP Server at %1$s as user %2$s on resource %3$s......",
+ server, username, resource));
+ }
+ } catch (XMPPException xmppException) {
+ String errorMsg =
+ "Login attempt to the XMPP Server at " + server + " with username - " + username + " failed.";
+ log.error(errorMsg);
+ throw new TransportHandlerException(errorMsg, xmppException);
+ }
+ } else {
+ String errorMsg = "Not connected to XMPP-Server to attempt Login. Please 'connectToServer' before Login";
+ throw new TransportHandlerException(errorMsg);
+ }
+ }
+
+
+ /**
+ * Sets a filter for all the incoming XMPP-Messages on the Sender's JID (XMPP-Account ID).
+ * Also creates a listener for the incoming messages and connects the listener to the
+ * XMPPConnection alongside the set filter.
+ *
+ * @param senderJID the JID (XMPP-Account ID of the sender) to which the filter is to be set.
+ */
+ protected void setFilterOnSender(String senderJID) {
+ filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter(
+ senderJID));
+ listener = new PacketListener() {
+ @Override
+ public void processPacket(Packet packet) {
+ if (packet instanceof Message) {
+ final Message xmppMessage = (Message) packet;
+ Thread msgProcessThread = new Thread() {
+ public void run() {
+ processIncomingMessage(xmppMessage);
+ }
+ };
+ msgProcessThread.setDaemon(true);
+ msgProcessThread.start();
+ }
+ }
+ };
+
+ connection.addPacketListener(listener, filter);
+ }
+
+
+ /**
+ * Sets a filter for all the incoming XMPP-Messages on the Receiver's JID (XMPP-Account ID).
+ * Also creates a listener for the incoming messages and connects the listener to the
+ * XMPPConnection alongside the set filter.
+ *
+ * @param receiverJID the JID (XMPP-Account ID of the receiver) to which the filter is to be
+ * set.
+ */
+ protected void setFilterOnReceiver(String receiverJID) {
+ filter = new AndFilter(new PacketTypeFilter(Message.class), new ToContainsFilter(
+ receiverJID));
+ listener = new PacketListener() {
+ @Override
+ public void processPacket(Packet packet) {
+ if (packet instanceof Message) {
+ final Message xmppMessage = (Message) packet;
+ Thread msgProcessThread = new Thread() {
+ public void run() {
+ processIncomingMessage(xmppMessage);
+ }
+ };
+ msgProcessThread.setDaemon(true);
+ msgProcessThread.start();
+ }
+ }
+ };
+
+ connection.addPacketListener(listener, filter);
+ }
+
+
+ /**
+ * Sets a filter for all the incoming XMPP-Messages on the From-JID & To-JID (XMPP-Account IDs)
+ * passed in. Also creates a listener for the incoming messages and connects the listener to
+ * the XMPPConnection alongside the set filter.
+ *
+ * @param senderJID the From-JID (XMPP-Account ID) to which the filter is to be set.
+ * @param receiverJID the To-JID (XMPP-Account ID) to which the filter is to be set.
+ * @param andCondition if true: then filter is set with 'AND' operator (senderJID &&
+ * receiverJID),
+ * if false: then the filter is set with 'OR' operator (senderJID |
+ * receiverJID)
+ */
+ protected void setMessageFilterAndListener(String senderJID, String receiverJID, boolean
+ andCondition) {
+ PacketFilter jidFilter;
+
+ if (andCondition) {
+ jidFilter = new AndFilter(new FromContainsFilter(senderJID), new ToContainsFilter(
+ receiverJID));
+ } else {
+ jidFilter = new OrFilter(new FromContainsFilter(senderJID), new ToContainsFilter(
+ receiverJID));
+ }
+
+ filter = new AndFilter(new PacketTypeFilter(Message.class), jidFilter);
+ listener = new PacketListener() {
+ @Override
+ public void processPacket(Packet packet) {
+ if (packet instanceof Message) {
+ final Message xmppMessage = (Message) packet;
+ Thread msgProcessThread = new Thread() {
+ public void run() {
+ processIncomingMessage(xmppMessage);
+ }
+ };
+ msgProcessThread.setDaemon(true);
+ msgProcessThread.start();
+ }
+ }
+ };
+
+ connection.addPacketListener(listener, filter);
+ }
+
+
+ /**
+ * Sends an XMPP message. Calls the overloaded method with Subject set to "Reply-From-Device"
+ *
+ * @param JID the JID (XMPP Account ID) to which the message is to be sent to.
+ * @param message the XMPP-Message that is to be sent.
+ */
+ protected void sendXMPPMessage(String JID, String message) {
+ sendXMPPMessage(JID, message, "XMPP-Message");
+ }
+
+
+ /**
+ * Overloaded method to send an XMPP message. Includes the subject to be mentioned in the
+ * message that is sent.
+ *
+ * @param JID the JID (XMPP Account ID) to which the message is to be sent to.
+ * @param message the XMPP-Message that is to be sent.
+ * @param subject the subject that the XMPP-Message would carry.
+ */
+ protected void sendXMPPMessage(String JID, String message, String subject) {
+ Message xmppMessage = new Message();
+ xmppMessage.setTo(JID);
+ xmppMessage.setSubject(subject);
+ xmppMessage.setBody(message);
+ xmppMessage.setType(Message.Type.chat);
+ sendXMPPMessage(JID, xmppMessage);
+ }
+
+
+ /**
+ * Sends an XMPP message.
+ *
+ * @param JID the JID (XMPP Account ID) to which the message is to be sent to.
+ * @param xmppMessage the XMPP-Message that is to be sent.
+ */
+ protected void sendXMPPMessage(String JID, Message xmppMessage) {
+ connection.sendPacket(xmppMessage);
+ if (log.isDebugEnabled()) {
+ log.debug("Message: '" + xmppMessage.getBody() + "' sent to XMPP JID [" + JID +
+ "] sent successfully.");
+ }
+ }
+
+
+ /**
+ * Disables default debugger provided by the XMPPConnection.
+ */
+ protected void disableDebugger() {
+ connection.DEBUG_ENABLED = false;
+ }
+
+
+ /**
+ * Closes the connection to the XMPP Server.
+ */
+ public void closeConnection() {
+ if (connection != null && isConnected()) {
+ connection.disconnect();
+ }
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java
new file mode 100644
index 000000000..fdb271e79
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.ui.AgentUI;
+
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Sequence;
+import javax.sound.midi.Sequencer;
+import javax.sound.sampled.Clip;
+import javax.swing.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * This class use to emulate virtual hardware functionality
+ */
+public class VirtualHardwareManager {
+
+ private static final Log log = LogFactory.getLog(VirtualHardwareManager.class);
+
+ private static VirtualHardwareManager virtualHardwareManager;
+
+ private AgentUI agentUI;
+ private Sequencer sequencer = null;
+
+ private int temperature = 30, humidity = 30;
+ private int temperatureMin = 20, temperatureMax = 50, humidityMin = 20, humidityMax = 50;
+ private int temperatureSVF = 50, humiditySVF = 50;
+ private boolean isTemperatureRandomized, isHumidityRandomized;
+ private boolean isTemperatureSmoothed, isHumiditySmoothed;
+
+ private VirtualHardwareManager(){
+ }
+
+ public static VirtualHardwareManager getInstance(){
+ if (virtualHardwareManager == null){
+ virtualHardwareManager = new VirtualHardwareManager();
+ }
+ return virtualHardwareManager;
+ }
+
+ public void init(){
+ try {
+ // Set System L&F for Device UI
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (UnsupportedLookAndFeelException e) {
+ log.error(
+ "'UnsupportedLookAndFeelException' error occurred whilst initializing the" +
+ " Agent UI.");
+ } catch (ClassNotFoundException e) {
+ log.error(
+ "'ClassNotFoundException' error occurred whilst initializing the Agent UI.");
+ } catch (InstantiationException e) {
+ log.error(
+ "'InstantiationException' error occurred whilst initializing the Agent UI.");
+ } catch (IllegalAccessException e) {
+ log.error(
+ "'IllegalAccessException' error occurred whilst initializing the Agent UI.");
+ }
+ java.awt.EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ agentUI = new AgentUI();
+ agentUI.setVisible(true);
+ }
+ });
+ setAudioSequencer();
+ }
+
+ /**
+ * Get temperature from emulated device
+ * @return Temperature
+ */
+ public int getTemperature() {
+ if (isTemperatureRandomized) {
+ temperature = getRandom(temperatureMax, temperatureMin, temperature,
+ isTemperatureSmoothed, temperatureSVF);
+ agentUI.updateTemperature(temperature);
+ }
+ return temperature;
+ }
+
+ public void setTemperature(int temperature) {
+ this.temperature = temperature;
+ }
+
+ /**
+ * Get humidity from emulated device
+ * @return Humidity
+ */
+ public int getHumidity() {
+ if (isHumidityRandomized) {
+ humidity = getRandom(humidityMax, humidityMin, humidity, isHumiditySmoothed,
+ humiditySVF);
+ agentUI.updateHumidity(humidity);
+ }
+ return humidity;
+ }
+
+ public void setHumidity(int humidity) {
+ this.humidity = humidity;
+ }
+
+ public void setTemperatureMin(int temperatureMin) {
+ this.temperatureMin = temperatureMin;
+ }
+
+ public void setTemperatureMax(int temperatureMax) {
+ this.temperatureMax = temperatureMax;
+ }
+
+ public void setHumidityMin(int humidityMin) {
+ this.humidityMin = humidityMin;
+ }
+
+ public void setHumidityMax(int humidityMax) {
+ this.humidityMax = humidityMax;
+ }
+
+ public void setIsHumidityRandomized(boolean isHumidityRandomized) {
+ this.isHumidityRandomized = isHumidityRandomized;
+ }
+
+ public void setIsTemperatureRandomized(boolean isTemperatureRandomized) {
+ this.isTemperatureRandomized = isTemperatureRandomized;
+ }
+
+ public void setTemperatureSVF(int temperatureSVF) {
+ this.temperatureSVF = temperatureSVF;
+ }
+
+ public void setHumiditySVF(int humiditySVF) {
+ this.humiditySVF = humiditySVF;
+ }
+
+ public void setIsTemperatureSmoothed(boolean isTemperatureSmoothed) {
+ this.isTemperatureSmoothed = isTemperatureSmoothed;
+ }
+
+ public void setIsHumiditySmoothed(boolean isHumiditySmoothed) {
+ this.isHumiditySmoothed = isHumiditySmoothed;
+ }
+
+ public void changeAlarmStatus(boolean isOn) {
+ agentUI.setAlarmStatus(isOn);
+
+ if (isOn) {
+ sequencer.start();
+ } else {
+ sequencer.stop();
+ }
+ }
+
+ private int getRandom(int max, int min, int current, boolean isSmoothed, int svf) {
+ if (isSmoothed) {
+ int offset = (max - min) * svf / 100;
+ double mx = current + offset;
+ max = (mx > max) ? max : (int) Math.round(mx);
+ double mn = current - offset;
+ min = (mn < min) ? min : (int) Math.round(mn);
+ }
+ try {
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ return secureRandom.nextInt(max - min) + min;
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA1PRNG algorithm could not be found.");
+ }
+ }
+
+ private void setAudioSequencer() {
+ InputStream audioSrc = AgentUtilOperations.class.getResourceAsStream(
+ "/" + AgentConstants.AUDIO_FILE_NAME);
+ Sequence sequence;
+
+ try {
+ sequence = MidiSystem.getSequence(audioSrc);
+ sequencer = MidiSystem.getSequencer();
+ if(sequencer != null) {
+ sequencer.open();
+ sequencer.setSequence(sequence);
+ sequencer.setLoopCount(Clip.LOOP_CONTINUOUSLY);
+ }
+ } catch (InvalidMidiDataException e) {
+ log.error("AudioReader: Error whilst setting MIDI Audio reader sequence");
+ } catch (IOException e) {
+ log.error("AudioReader: Error whilst getting audio sequence from stream");
+ } catch (MidiUnavailableException e) {
+ log.error("AudioReader: Error whilst openning MIDI Audio reader sequencer");
+ }
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java
new file mode 100644
index 000000000..15b544389
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java
@@ -0,0 +1,910 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.ui;
+
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.VirtualHardwareManager;
+
+import java.awt.*;
+import java.net.URL;
+import java.util.Calendar;
+import javax.swing.*;
+
+public class AgentUI extends JFrame {
+
+ private boolean isTemperatureRandomized, isHumidityRandomized;
+ private boolean isTemperatureSmoothed, isHumiditySmoothed;
+
+ private volatile boolean isAlarmOn = false;
+
+ private JLabel picLabelBulbOn, picLabelBulbOff;
+
+ // Variables declaration - do not modify
+ private JCheckBox chkbxEmulate;
+ private JCheckBox chkbxHumidityRandom;
+ private JCheckBox chkbxHumiditySmooth;
+ private JCheckBox chkbxTemperatureRandom;
+ private JCheckBox chkbxTemperatureSmooth;
+ private JComboBox cmbInterface;
+ private JComboBox cmbPeriod;
+ private JComboBox cmbProtocol;
+ private JLabel jLabel1;
+ private JLabel jLabel10;
+ private JLabel jLabel11;
+ private JLabel jLabel12;
+ private JLabel jLabel2;
+ private JLabel jLabel20;
+ private JLabel jLabel23;
+ private JLabel jLabel24;
+ private JLabel jLabel25;
+ private JLabel jLabel3;
+ private JLabel jLabel4;
+ private JLabel jLabel5;
+ private JLabel jLabel6;
+ private JLabel jLabel7;
+ private JLabel jLabel8;
+ private JLabel jLabel9;
+ private JPanel jPanel1;
+ private JPanel jPanel2;
+ private JPanel jPanel3;
+ private JPanel jPanel4;
+ private JPanel jPanel6;
+ private JPanel jPanel7;
+ private JPanel jPanel8;
+ private JPanel jPanel9;
+ private JSeparator jSeparator1;
+ private JSeparator jSeparator5;
+ private JLabel lblAgentName;
+ private JLabel lblStatus;
+ private JPanel pnlBulbStatus;
+ private JSpinner spinnerHumidity;
+ private JSpinner spinnerInterval;
+ private JSpinner spinnerTemperature;
+ private JTextField txtHumidityMax;
+ private JTextField txtHumidityMin;
+ private JTextField txtHumiditySVF;
+ private JTextField txtTemperatureMax;
+ private JTextField txtTemperatureMin;
+ private JTextField txtTemperatureSVF;
+ // End of variables declaration
+
+ private Runnable uiUpdater = new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ pnlBulbStatus.removeAll();
+ pnlBulbStatus.add(isAlarmOn ? picLabelBulbOn : picLabelBulbOff);
+ pnlBulbStatus.updateUI();
+ lblStatus.setText(AgentManager.getInstance().getAgentStatus());
+ if (isTemperatureRandomized) {
+ txtTemperatureMinActionPerformed(null);
+ txtTemperatureMaxActionPerformed(null);
+ if (isTemperatureSmoothed) {
+ txtTemperatureSVFActionPerformed(null);
+ }
+ }
+ if (isHumidityRandomized) {
+ txtHumidityMinActionPerformed(null);
+ txtHumidityMaxActionPerformed(null);
+ if (isHumiditySmoothed) {
+ txtHumiditySVFActionPerformed(null);
+ }
+ }
+ }
+ });
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+
+ /**
+ * Creates new form AgentUI
+ */
+ public AgentUI() {
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ private void initComponents() {
+
+ lblAgentName = new JLabel();
+ jLabel2 = new JLabel();
+ jPanel1 = new JPanel();
+ jLabel3 = new JLabel();
+ pnlBulbStatus = new JPanel();
+ jPanel2 = new JPanel();
+ jLabel4 = new JLabel();
+ chkbxTemperatureRandom = new JCheckBox();
+ jSeparator1 = new JSeparator();
+ jPanel7 = new JPanel();
+ jLabel5 = new JLabel();
+ txtTemperatureMin = new JTextField();
+ jLabel6 = new JLabel();
+ txtTemperatureMax = new JTextField();
+ jLabel10 = new JLabel();
+ txtTemperatureSVF = new JTextField();
+ spinnerTemperature = new JSpinner();
+ chkbxTemperatureSmooth = new JCheckBox();
+ jPanel6 = new JPanel();
+ jLabel20 = new JLabel();
+ lblStatus = new JLabel();
+ jPanel8 = new JPanel();
+ jLabel23 = new JLabel();
+ chkbxHumidityRandom = new JCheckBox();
+ jSeparator5 = new JSeparator();
+ jPanel9 = new JPanel();
+ jLabel24 = new JLabel();
+ txtHumidityMin = new JTextField();
+ jLabel25 = new JLabel();
+ txtHumidityMax = new JTextField();
+ txtHumiditySVF = new JTextField();
+ jLabel11 = new JLabel();
+ spinnerHumidity = new JSpinner();
+ chkbxHumiditySmooth = new JCheckBox();
+ jPanel3 = new JPanel();
+ jLabel7 = new JLabel();
+ spinnerInterval = new JSpinner();
+ jLabel8 = new JLabel();
+ jLabel9 = new JLabel();
+ cmbProtocol = new JComboBox();
+ jLabel12 = new JLabel();
+ cmbInterface = new JComboBox();
+ jPanel4 = new JPanel();
+ chkbxEmulate = new JCheckBox();
+ cmbPeriod = new JComboBox();
+ jLabel1 = new JLabel();
+
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ setTitle("Fire Alarm Emulator");
+ setResizable(false);
+ Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation(dim.width / 2 - 650 / 2, dim.height / 2 - 440 / 2);
+
+ lblAgentName.setFont(new Font("Cantarell", 1, 24)); // NOI18N
+ lblAgentName.setHorizontalAlignment(SwingConstants.LEFT);
+ lblAgentName.setText("Device Name: " + AgentManager.getInstance().getDeviceName());
+
+ Calendar now = Calendar.getInstance();
+ int currentYear = now.get(Calendar.YEAR);
+ jLabel2.setHorizontalAlignment(SwingConstants.CENTER);
+ jLabel2.setText("Copyright (c) " + currentYear + ", WSO2 Inc.");
+
+ jPanel1.setBackground(new Color(220, 220, 220));
+
+ jLabel3.setFont(new Font("Cantarell", 0, 18)); // NOI18N
+ jLabel3.setHorizontalAlignment(SwingConstants.CENTER);
+ jLabel3.setText("Alarm Status");
+
+ pnlBulbStatus.setBackground(new Color(220, 220, 220));
+
+ GroupLayout pnlBulbStatusLayout = new GroupLayout(pnlBulbStatus);
+ pnlBulbStatus.setLayout(pnlBulbStatusLayout);
+ pnlBulbStatusLayout.setHorizontalGroup(
+ pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGap(0, 0, Short.MAX_VALUE)
+ );
+ pnlBulbStatusLayout.setVerticalGroup(
+ pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGap(0, 167, Short.MAX_VALUE)
+ );
+
+ GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel1Layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
+ .addComponent(pnlBulbStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel3, GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel3)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pnlBulbStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap())
+ );
+
+ jPanel2.setBackground(new Color(220, 220, 220));
+
+ jLabel4.setFont(new Font("Cantarell", 0, 18)); // NOI18N
+ jLabel4.setHorizontalAlignment(SwingConstants.CENTER);
+ jLabel4.setText("Temperature");
+
+ chkbxTemperatureRandom.setText("Randomize Data");
+ chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxTemperatureRandomActionPerformed(evt);
+ }
+ });
+
+ jSeparator1.setOrientation(SwingConstants.VERTICAL);
+
+ jPanel7.setBackground(new Color(220, 220, 220));
+
+ jLabel5.setHorizontalAlignment(SwingConstants.LEFT);
+ jLabel5.setText("Min");
+
+ txtTemperatureMin.setHorizontalAlignment(JTextField.CENTER);
+ txtTemperatureMin.setText("20");
+ txtTemperatureMin.setEnabled(false);
+ txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureMinActionPerformed(evt);
+ }
+ });
+
+ jLabel6.setHorizontalAlignment(SwingConstants.RIGHT);
+ jLabel6.setText("Max");
+
+ txtTemperatureMax.setHorizontalAlignment(JTextField.CENTER);
+ txtTemperatureMax.setText("50");
+ txtTemperatureMax.setEnabled(false);
+ txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureMaxActionPerformed(evt);
+ }
+ });
+
+ jLabel10.setHorizontalAlignment(SwingConstants.RIGHT);
+ jLabel10.setText("SV %");
+
+ txtTemperatureSVF.setHorizontalAlignment(JTextField.CENTER);
+ txtTemperatureSVF.setText("50");
+ txtTemperatureSVF.setEnabled(false);
+ txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureSVFActionPerformed(evt);
+ }
+ });
+
+ GroupLayout jPanel7Layout = new GroupLayout(jPanel7);
+ jPanel7.setLayout(jPanel7Layout);
+ jPanel7Layout.setHorizontalGroup(
+ jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel7Layout.createSequentialGroup()
+ .addComponent(jLabel5)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureMin, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel6)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel10)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureSVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ jPanel7Layout.setVerticalGroup(
+ jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup()
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel7Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(txtTemperatureMin, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(txtTemperatureMax, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel6)
+ .addComponent(jLabel5)
+ .addComponent(jLabel10)
+ .addComponent(txtTemperatureSVF, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+ .addGap(35, 35, 35))
+ );
+
+ spinnerTemperature.setFont(new Font("Cantarell", 1, 24)); // NOI18N
+ spinnerTemperature.setModel(new SpinnerNumberModel(30, 0, 100, 1));
+ spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerTemperatureStateChanged(evt);
+ }
+ });
+
+ chkbxTemperatureSmooth.setText("Smooth Variation");
+ chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxTemperatureSmoothActionPerformed(evt);
+ }
+ });
+
+ GroupLayout jPanel2Layout = new GroupLayout(jPanel2);
+ jPanel2.setLayout(jPanel2Layout);
+ jPanel2Layout.setHorizontalGroup(
+ jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
+ .addComponent(jLabel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(spinnerTemperature))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addComponent(chkbxTemperatureRandom)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(chkbxTemperatureSmooth)))
+ .addContainerGap())
+ );
+ jPanel2Layout.setVerticalGroup(
+ jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(jSeparator1)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addGroup(jPanel2Layout.createParallelGroup(
+
+ GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxTemperatureRandom)
+ .addComponent(chkbxTemperatureSmooth))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addComponent(jLabel4, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerTemperature)))
+ .addContainerGap())
+ );
+
+ jPanel6.setBackground(new Color(253, 254, 209));
+
+ jLabel20.setText("Connection Status:");
+ jLabel20.setVerticalTextPosition(SwingConstants.TOP);
+
+ lblStatus.setFont(new Font("Cantarell", 1, 15)); // NOI18N
+ lblStatus.setText("Not Connected");
+
+ GroupLayout jPanel6Layout = new GroupLayout(jPanel6);
+ jPanel6.setLayout(jPanel6Layout);
+ jPanel6Layout.setHorizontalGroup(
+ jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel6Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel20)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addContainerGap())
+ );
+ jPanel6Layout.setVerticalGroup(
+ jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup()
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
+ .addComponent(jLabel20, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel6Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(lblStatus)))
+ .addContainerGap())
+ );
+
+ jPanel8.setBackground(new Color(220, 220, 220));
+
+ jLabel23.setFont(new Font("Cantarell", 0, 18)); // NOI18N
+ jLabel23.setHorizontalAlignment(SwingConstants.CENTER);
+ jLabel23.setText("Humidity");
+
+ chkbxHumidityRandom.setText("Randomize Data");
+ chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxHumidityRandomActionPerformed(evt);
+ }
+ });
+
+ jSeparator5.setOrientation(SwingConstants.VERTICAL);
+
+ jPanel9.setBackground(new Color(220, 220, 220));
+
+ jLabel24.setHorizontalAlignment(SwingConstants.LEFT);
+ jLabel24.setText("Min");
+
+ txtHumidityMin.setHorizontalAlignment(JTextField.CENTER);
+ txtHumidityMin.setText("20");
+ txtHumidityMin.setEnabled(false);
+ txtHumidityMin.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumidityMinActionPerformed(evt);
+ }
+ });
+
+ jLabel25.setHorizontalAlignment(SwingConstants.RIGHT);
+ jLabel25.setText("Max");
+
+ txtHumidityMax.setHorizontalAlignment(JTextField.CENTER);
+ txtHumidityMax.setText("50");
+ txtHumidityMax.setEnabled(false);
+ txtHumidityMax.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumidityMaxActionPerformed(evt);
+ }
+ });
+
+ txtHumiditySVF.setHorizontalAlignment(JTextField.CENTER);
+ txtHumiditySVF.setText("50");
+ txtHumiditySVF.setEnabled(false);
+ txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumiditySVFActionPerformed(evt);
+ }
+ });
+
+ jLabel11.setHorizontalAlignment(SwingConstants.RIGHT);
+ jLabel11.setText("SV %");
+
+ GroupLayout jPanel9Layout = new GroupLayout(jPanel9);
+ jPanel9.setLayout(jPanel9Layout);
+ jPanel9Layout.setHorizontalGroup(
+ jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel9Layout.createSequentialGroup()
+ .addComponent(jLabel24)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumidityMin, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel25)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumidityMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel11)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumiditySVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ jPanel9Layout.setVerticalGroup(
+ jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup()
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel11)
+ .addComponent(txtHumiditySVF, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+ .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(txtHumidityMin, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(txtHumidityMax, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel25)
+ .addComponent(jLabel24)))
+ .addGap(35, 35, 35))
+ );
+
+ spinnerHumidity.setFont(new Font("Cantarell", 1, 24)); // NOI18N
+ spinnerHumidity.setModel(new SpinnerNumberModel(30, 0, 100, 1));
+ spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerHumidityStateChanged(evt);
+ }
+ });
+
+ chkbxHumiditySmooth.setText("Smooth Variation");
+ chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxHumiditySmoothActionPerformed(evt);
+ }
+ });
+
+ GroupLayout jPanel8Layout = new GroupLayout(jPanel8);
+ jPanel8.setLayout(jPanel8Layout);
+ jPanel8Layout.setHorizontalGroup(
+ jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
+ .addComponent(spinnerHumidity))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jSeparator5, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
+ .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addComponent(chkbxHumidityRandom)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(chkbxHumiditySmooth)))
+ .addContainerGap())
+ );
+ jPanel8Layout.setVerticalGroup(
+ jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(jSeparator5)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addGroup(jPanel8Layout.createParallelGroup(
+ GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxHumidityRandom)
+ .addComponent(chkbxHumiditySmooth))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 1, Short.MAX_VALUE))
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerHumidity)))
+ .addContainerGap())
+ );
+
+ jPanel3.setBackground(new Color(207, 233, 234));
+
+ jLabel7.setText("Data Push Interval:");
+
+ spinnerInterval.setModel(new SpinnerNumberModel(Integer.valueOf(AgentManager.getInstance().getPushInterval()), Integer.valueOf(1), null, Integer.valueOf(1)));
+ spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerIntervalStateChanged(evt);
+ }
+ });
+
+ jLabel8.setText("Seconds");
+
+ jLabel9.setText("Protocol:");
+
+ cmbProtocol.setModel(new DefaultComboBoxModel(new String[] { "MQTT", "XMPP", "HTTP" }));
+ cmbProtocol.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbProtocolActionPerformed(evt);
+ }
+ });
+
+ jLabel12.setText("Interface:");
+
+ cmbInterface.setModel(new DefaultComboBoxModel(new String[] { "eth0" }));
+ cmbInterface.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbInterfaceActionPerformed(evt);
+ }
+ });
+
+ GroupLayout jPanel3Layout = new GroupLayout(jPanel3);
+ jPanel3.setLayout(jPanel3Layout);
+ jPanel3Layout.setHorizontalGroup(
+ jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel3Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel7)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerInterval, GroupLayout.PREFERRED_SIZE, 55, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel8)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel12)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbInterface, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel9)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbProtocol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+ jPanel3Layout.setVerticalGroup(
+ jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel12)
+ .addComponent(cmbInterface, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+ .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel7)
+ .addComponent(spinnerInterval, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel8)
+ .addComponent(jLabel9)
+ .addComponent(cmbProtocol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
+ .addContainerGap())
+ );
+
+ jPanel4.setBackground(new Color(169, 253, 173));
+
+ chkbxEmulate.setText("Emulate data");
+ chkbxEmulate.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxEmulateActionPerformed(evt);
+ }
+ });
+
+ cmbPeriod.setModel(new DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " }));
+ cmbPeriod.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbPeriodActionPerformed(evt);
+ }
+ });
+
+ jLabel1.setText("Emulation Period");
+
+ GroupLayout jPanel4Layout = new GroupLayout(jPanel4);
+ jPanel4.setLayout(jPanel4Layout);
+ jPanel4Layout.setHorizontalGroup(
+ jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel4Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(chkbxEmulate)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel1)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbPeriod, GroupLayout.PREFERRED_SIZE, 162, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+ jPanel4Layout.setVerticalGroup(
+ jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup()
+ .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel4Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxEmulate)
+ .addComponent(cmbPeriod, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel1))
+ .addContainerGap())
+ );
+
+ GroupLayout layout = new GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(lblAgentName, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel6, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(
+ GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel8, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addComponent(jLabel2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(lblAgentName, GroupLayout.PREFERRED_SIZE, 53, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jPanel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel8, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+ .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel2, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+
+ pack();
+
+ chkbxTemperatureSmooth.setEnabled(false);
+ chkbxTemperatureSmooth.setEnabled(false);
+
+ cmbInterface.removeAllItems();
+ for (String item : AgentManager.getInstance().getInterfaceList()){
+ cmbInterface.addItem(item);
+ }
+ cmbInterface.setEnabled(false);
+
+ cmbProtocol.removeAllItems();
+ for (String item : AgentManager.getInstance().getProtocolList()){
+ cmbProtocol.addItem(item);
+ }
+ cmbProtocol.setSelectedItem(AgentConstants.DEFAULT_PROTOCOL);
+
+ URL urlAlarmOn = this.getClass().getResource("/alarm-on.gif");
+ ImageIcon imageIconAlarmOn = new ImageIcon(urlAlarmOn);
+
+ URL urlAlarmOff = this.getClass().getResource("/alarm-off.gif");
+ ImageIcon imageIconAlarmOff = new ImageIcon(urlAlarmOff);
+
+ picLabelBulbOn = new JLabel(imageIconAlarmOn);
+ picLabelBulbOn.setSize(pnlBulbStatus.getSize());
+
+ picLabelBulbOff = new JLabel(imageIconAlarmOff);
+ picLabelBulbOff.setSize(pnlBulbStatus.getSize());
+
+ new Thread(uiUpdater).start();
+
+ AgentManager.getInstance().setDeviceReady(true);
+ }
+
+
+ private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) {
+ isTemperatureRandomized = chkbxTemperatureRandom.isSelected();
+ VirtualHardwareManager.getInstance().setIsTemperatureRandomized(isTemperatureRandomized);
+ spinnerTemperature.setEnabled(!isTemperatureRandomized);
+ txtTemperatureMax.setEnabled(isTemperatureRandomized);
+ txtTemperatureMin.setEnabled(isTemperatureRandomized);
+ chkbxTemperatureSmooth.setEnabled(isTemperatureRandomized);
+ txtTemperatureSVF.setEnabled(isTemperatureRandomized && isTemperatureSmoothed);
+ }
+
+ private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) {
+ isHumidityRandomized = chkbxHumidityRandom.isSelected();
+ VirtualHardwareManager.getInstance().setIsHumidityRandomized(isHumidityRandomized);
+ spinnerHumidity.setEnabled(!isHumidityRandomized);
+ txtHumidityMax.setEnabled(isHumidityRandomized);
+ txtHumidityMin.setEnabled(isHumidityRandomized);
+ chkbxHumiditySmooth.setEnabled(isHumidityRandomized);
+ txtTemperatureSVF.setEnabled(isHumidityRandomized && isHumiditySmoothed);
+ }
+
+ private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) {
+ if (!isTemperatureRandomized) {
+ try {
+ int temperature = Integer.parseInt(spinnerTemperature.getValue().toString());
+ VirtualHardwareManager.getInstance().setTemperature(temperature);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE);
+ spinnerTemperature.setValue(VirtualHardwareManager.getInstance().getTemperature());
+ }
+ }
+ }
+
+ private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) {
+ if (!isHumidityRandomized) {
+ try {
+ int humidity = Integer.parseInt(spinnerHumidity.getValue().toString());
+ VirtualHardwareManager.getInstance().setHumidity(humidity);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE);
+ spinnerHumidity.setValue(VirtualHardwareManager.getInstance().getHumidity());
+ }
+ }
+ }
+
+ private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int temperature = Integer.parseInt(txtTemperatureMin.getText());
+ VirtualHardwareManager.getInstance().setTemperatureMin(temperature);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtTemperatureMin.setText("20");
+ }
+ }
+
+ private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int temperature = Integer.parseInt(txtTemperatureMax.getText());
+ VirtualHardwareManager.getInstance().setTemperatureMax(temperature);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtTemperatureMax.setText("50");
+ }
+ }
+
+ private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int humidity = Integer.parseInt(txtHumidityMin.getText());
+ VirtualHardwareManager.getInstance().setHumidityMin(humidity);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtHumidityMin.setText("20");
+ }
+ }
+
+ private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int humidity = Integer.parseInt(txtHumidityMax.getText());
+ VirtualHardwareManager.getInstance().setHumidityMax(humidity);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtHumidityMax.setText("50");
+ }
+ }
+
+ private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) {
+ try {
+ int interval = Integer.parseInt(spinnerInterval.getValue().toString());
+ AgentManager.getInstance().setPushInterval(interval);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid time interval value", "Error", JOptionPane.ERROR_MESSAGE);
+ spinnerInterval.setValue(5);
+ }
+ }
+
+ private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) {
+ AgentManager.getInstance().setInterface(cmbInterface.getSelectedIndex());
+ }
+
+ private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) {
+ if (cmbProtocol.getSelectedIndex() != -1 && cmbProtocol.getItemAt(
+ cmbProtocol.getSelectedIndex()).equals(AgentConstants.HTTP_PROTOCOL)) {
+ cmbInterface.setEnabled(true);
+ } else {
+ cmbInterface.setEnabled(false);
+ }
+
+ AgentManager.getInstance().setProtocol(cmbProtocol.getSelectedIndex());
+
+ }
+
+ private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int temperatureSVF = Integer.parseInt(txtTemperatureSVF.getText());
+ VirtualHardwareManager.getInstance().setTemperatureSVF(temperatureSVF);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtTemperatureSVF.setText("50");
+ }
+ }
+
+ private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) {
+ try {
+ int humiditySVF = Integer.parseInt(txtHumiditySVF.getText());
+ VirtualHardwareManager.getInstance().setHumiditySVF(humiditySVF);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE);
+ txtHumiditySVF.setText("50");
+ }
+ }
+
+ private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) {
+ isTemperatureSmoothed = chkbxTemperatureSmooth.isSelected();
+ txtTemperatureSVF.setEnabled(isTemperatureSmoothed);
+ VirtualHardwareManager.getInstance().setIsTemperatureSmoothed(isTemperatureSmoothed);
+ }
+
+ private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) {
+ isHumiditySmoothed = chkbxHumiditySmooth.isSelected();
+ txtHumiditySVF.setEnabled(isHumiditySmoothed);
+ VirtualHardwareManager.getInstance().setIsHumiditySmoothed(isHumiditySmoothed);
+ }
+
+ private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) {
+ // TODO add your handling code here:
+ }
+
+ private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) {
+ // TODO add your handling code here:
+ }
+
+ public void setAlarmStatus(boolean isAlarmOn) {
+ this.isAlarmOn = isAlarmOn;
+ }
+
+ public void updateTemperature(int temperature) {
+ spinnerTemperature.setValue(temperature);
+ spinnerTemperature.updateUI();
+ }
+
+ public void updateHumidity(int humidity) {
+ spinnerHumidity.setValue(humidity);
+ spinnerHumidity.updateUI();
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif
new file mode 100644
index 000000000..c346605ad
Binary files /dev/null and b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif differ
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-on.gif b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-on.gif
new file mode 100644
index 000000000..d7c83f6aa
Binary files /dev/null and b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-on.gif differ
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties
new file mode 100644
index 000000000..ba7e9922b
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties
@@ -0,0 +1,35 @@
+ad#
+# Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#[Device-Configurations]
+server-name=WSO2IoTServer
+owner=shabirmean
+deviceId=t4ctwq8qfl11
+device-name=SMEAN_t4ctwq8qfl11
+controller-context=/virtual_firealarm/device
+scep-context=/virtual_firealarm_scep
+https-ep=https://localhost:9443
+http-ep=http://localhost:9763
+apim-ep=http://192.168.67.21:8281
+mqtt-ep=tcp://192.168.67.21:1883
+xmpp-ep=http://204.232.188.215:5222
+auth-method=token
+auth-token=79d68b50ae5f5a06e812889979b3453
+refresh-token=8bdda6359dddad218cff3354d5a8cb3b
+network-interface=en0
+push-interval=14
+xmpp-server-name=localhost
\ No newline at end of file
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid
new file mode 100644
index 000000000..d1a2241b2
Binary files /dev/null and b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid differ
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/build.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/build.xml
new file mode 100644
index 000000000..bc3a40444
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project VirtualAgentUI.
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf
new file mode 100644
index 000000000..328e8e5bc
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml
new file mode 100644
index 000000000..67a63a7f4
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml
@@ -0,0 +1,1420 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties
new file mode 100644
index 000000000..1a7c9fdef
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=e60df945
+build.xml.script.CRC32=7c331eea
+build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=e60df945
+nbproject/build-impl.xml.script.CRC32=18800575
+nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties
new file mode 100644
index 000000000..eda34e66d
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties
@@ -0,0 +1,2 @@
+compile.on.save=true
+user.properties.file=/home/lahiru/.netbeans/8.2/build.properties
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml
new file mode 100644
index 000000000..9009411f0
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ file:/home/lahiru/WSO2IOT/carbon-device-mgt-plugins/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties
new file mode 100644
index 000000000..fb798f614
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties
@@ -0,0 +1,73 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processor.options=
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/VirtualAgentUI.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.8
+javac.target=1.8
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=org.wso2.carbon.device.mgt.iot.agent.virtual.VirtualAgentUI
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml
new file mode 100644
index 000000000..438f1e6a3
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml
@@ -0,0 +1,15 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ VirtualAgentUI
+
+
+
+
+
+
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg
new file mode 100644
index 000000000..51d40cd83
Binary files /dev/null and b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg differ
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java
new file mode 100644
index 000000000..a2aa2116a
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java
@@ -0,0 +1,37 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.wso2.carbon.device.mgt.iot.agent.virtual;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import org.wso2.carbon.device.mgt.iot.agent.virtual.ui.AgentUI;
+
+/**
+ *
+ * @author charitha
+ */
+public class VirtualAgentUI {
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) {
+ try {
+ // Set System L&F
+ UIManager.setLookAndFeel(
+ UIManager.getSystemLookAndFeelClassName());
+ } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ // handle exception
+ }
+
+ java.awt.EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ new AgentUI().setVisible(true);
+ }
+ });
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form
new file mode 100644
index 000000000..43bc3e62e
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form
@@ -0,0 +1,779 @@
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java
new file mode 100644
index 000000000..e3b4e89f6
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java
@@ -0,0 +1,711 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.wso2.carbon.device.mgt.iot.agent.virtual.ui;
+
+/**
+ *
+ * @author charitha
+ */
+public class AgentUI extends javax.swing.JFrame {
+
+ /**
+ * Creates new form AgentUI
+ */
+ public AgentUI() {
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ lblAgentName = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jPanel1 = new javax.swing.JPanel();
+ jLabel3 = new javax.swing.JLabel();
+ pnlBulbStatus = new javax.swing.JPanel();
+ jPanel2 = new javax.swing.JPanel();
+ jLabel4 = new javax.swing.JLabel();
+ chkbxTemperatureRandom = new javax.swing.JCheckBox();
+ jSeparator1 = new javax.swing.JSeparator();
+ jPanel7 = new javax.swing.JPanel();
+ jLabel5 = new javax.swing.JLabel();
+ txtTemperatureMin = new javax.swing.JTextField();
+ jLabel6 = new javax.swing.JLabel();
+ txtTemperatureMax = new javax.swing.JTextField();
+ jLabel10 = new javax.swing.JLabel();
+ txtTemperatureSVF = new javax.swing.JTextField();
+ spinnerTemperature = new javax.swing.JSpinner();
+ chkbxTemperatureSmooth = new javax.swing.JCheckBox();
+ jPanel6 = new javax.swing.JPanel();
+ jLabel20 = new javax.swing.JLabel();
+ lblStatus = new javax.swing.JLabel();
+ jPanel8 = new javax.swing.JPanel();
+ jLabel23 = new javax.swing.JLabel();
+ chkbxHumidityRandom = new javax.swing.JCheckBox();
+ jSeparator5 = new javax.swing.JSeparator();
+ jPanel9 = new javax.swing.JPanel();
+ jLabel24 = new javax.swing.JLabel();
+ txtHumidityMin = new javax.swing.JTextField();
+ jLabel25 = new javax.swing.JLabel();
+ txtHumidityMax = new javax.swing.JTextField();
+ txtHumiditySVF = new javax.swing.JTextField();
+ jLabel11 = new javax.swing.JLabel();
+ spinnerHumidity = new javax.swing.JSpinner();
+ chkbxHumiditySmooth = new javax.swing.JCheckBox();
+ jPanel3 = new javax.swing.JPanel();
+ jLabel7 = new javax.swing.JLabel();
+ spinnerInterval = new javax.swing.JSpinner();
+ jLabel8 = new javax.swing.JLabel();
+ jLabel9 = new javax.swing.JLabel();
+ cmbProtocol = new javax.swing.JComboBox();
+ jLabel12 = new javax.swing.JLabel();
+ cmbInterface = new javax.swing.JComboBox();
+ jPanel4 = new javax.swing.JPanel();
+ chkbxEmulate = new javax.swing.JCheckBox();
+ cmbPeriod = new javax.swing.JComboBox();
+ jLabel1 = new javax.swing.JLabel();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+ setTitle("Fire Alarm Emulator");
+ setResizable(false);
+
+ lblAgentName.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N
+ lblAgentName.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+ lblAgentName.setText("Device Name: WSO2 IoT Virtual Agent");
+
+ jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jLabel2.setText("Copyright (c) 2015, WSO2 Inc.");
+
+ jPanel1.setBackground(new java.awt.Color(220, 220, 220));
+
+ jLabel3.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N
+ jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jLabel3.setText("Bulb Status");
+
+ pnlBulbStatus.setBackground(new java.awt.Color(220, 220, 220));
+
+ javax.swing.GroupLayout pnlBulbStatusLayout = new javax.swing.GroupLayout(pnlBulbStatus);
+ pnlBulbStatus.setLayout(pnlBulbStatusLayout);
+ pnlBulbStatusLayout.setHorizontalGroup(
+ pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 0, Short.MAX_VALUE)
+ );
+ pnlBulbStatusLayout.setVerticalGroup(
+ pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 167, Short.MAX_VALUE)
+ );
+
+ javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel3)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap())
+ );
+
+ jPanel2.setBackground(new java.awt.Color(220, 220, 220));
+
+ jLabel4.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N
+ jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jLabel4.setText("Temperature");
+
+ chkbxTemperatureRandom.setText("Randomize Data");
+ chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxTemperatureRandomActionPerformed(evt);
+ }
+ });
+
+ jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL);
+
+ jPanel7.setBackground(new java.awt.Color(220, 220, 220));
+
+ jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+ jLabel5.setText("Min");
+
+ txtTemperatureMin.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtTemperatureMin.setText("20");
+ txtTemperatureMin.setEnabled(false);
+ txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureMinActionPerformed(evt);
+ }
+ });
+
+ jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+ jLabel6.setText("Max");
+
+ txtTemperatureMax.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtTemperatureMax.setText("50");
+ txtTemperatureMax.setEnabled(false);
+ txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureMaxActionPerformed(evt);
+ }
+ });
+
+ jLabel10.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+ jLabel10.setText("SV %");
+
+ txtTemperatureSVF.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtTemperatureSVF.setText("50");
+ txtTemperatureSVF.setEnabled(false);
+ txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtTemperatureSVFActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout jPanel7Layout = new javax.swing.GroupLayout(jPanel7);
+ jPanel7.setLayout(jPanel7Layout);
+ jPanel7Layout.setHorizontalGroup(
+ jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel7Layout.createSequentialGroup()
+ .addComponent(jLabel5)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel6)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel10)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ jPanel7Layout.setVerticalGroup(
+ jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel6)
+ .addComponent(jLabel5)
+ .addComponent(jLabel10)
+ .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(35, 35, 35))
+ );
+
+ spinnerTemperature.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N
+ spinnerTemperature.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1));
+ spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerTemperatureStateChanged(evt);
+ }
+ });
+
+ chkbxTemperatureSmooth.setText("Smooth Variation");
+ chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxTemperatureSmoothActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+ jPanel2.setLayout(jPanel2Layout);
+ jPanel2Layout.setHorizontalGroup(
+ jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(spinnerTemperature))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addComponent(chkbxTemperatureRandom)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(chkbxTemperatureSmooth)))
+ .addContainerGap())
+ );
+ jPanel2Layout.setVerticalGroup(
+ jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jSeparator1)
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxTemperatureRandom)
+ .addComponent(chkbxTemperatureSmooth))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(jPanel2Layout.createSequentialGroup()
+ .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerTemperature)))
+ .addContainerGap())
+ );
+
+ jPanel6.setBackground(new java.awt.Color(253, 254, 209));
+
+ jLabel20.setText("Connection Status:");
+ jLabel20.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
+
+ lblStatus.setFont(new java.awt.Font("Cantarell", 1, 15)); // NOI18N
+ lblStatus.setText("Not Connected");
+
+ javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
+ jPanel6.setLayout(jPanel6Layout);
+ jPanel6Layout.setHorizontalGroup(
+ jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel6Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel20)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGap(273, 273, 273))
+ );
+ jPanel6Layout.setVerticalGroup(
+ jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(jLabel20, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
+ .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+
+ jPanel8.setBackground(new java.awt.Color(220, 220, 220));
+
+ jLabel23.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N
+ jLabel23.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jLabel23.setText("Humidity");
+
+ chkbxHumidityRandom.setText("Randomize Data");
+ chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxHumidityRandomActionPerformed(evt);
+ }
+ });
+
+ jSeparator5.setOrientation(javax.swing.SwingConstants.VERTICAL);
+
+ jPanel9.setBackground(new java.awt.Color(220, 220, 220));
+
+ jLabel24.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+ jLabel24.setText("Min");
+
+ txtHumidityMin.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtHumidityMin.setText("20");
+ txtHumidityMin.setEnabled(false);
+ txtHumidityMin.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumidityMinActionPerformed(evt);
+ }
+ });
+
+ jLabel25.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+ jLabel25.setText("Max");
+
+ txtHumidityMax.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtHumidityMax.setText("50");
+ txtHumidityMax.setEnabled(false);
+ txtHumidityMax.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumidityMaxActionPerformed(evt);
+ }
+ });
+
+ txtHumiditySVF.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+ txtHumiditySVF.setText("50");
+ txtHumiditySVF.setEnabled(false);
+ txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtHumiditySVFActionPerformed(evt);
+ }
+ });
+
+ jLabel11.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+ jLabel11.setText("SV %");
+
+ javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9);
+ jPanel9.setLayout(jPanel9Layout);
+ jPanel9Layout.setHorizontalGroup(
+ jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel9Layout.createSequentialGroup()
+ .addComponent(jLabel24)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel25)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel11)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ jPanel9Layout.setVerticalGroup(
+ jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel11)
+ .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel25)
+ .addComponent(jLabel24)))
+ .addGap(35, 35, 35))
+ );
+
+ spinnerHumidity.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N
+ spinnerHumidity.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1));
+ spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerHumidityStateChanged(evt);
+ }
+ });
+
+ chkbxHumiditySmooth.setText("Smooth Variation");
+ chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxHumiditySmoothActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout jPanel8Layout = new javax.swing.GroupLayout(jPanel8);
+ jPanel8.setLayout(jPanel8Layout);
+ jPanel8Layout.setHorizontalGroup(
+ jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(spinnerHumidity))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addComponent(chkbxHumidityRandom)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(chkbxHumiditySmooth)))
+ .addContainerGap())
+ );
+ jPanel8Layout.setVerticalGroup(
+ jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jSeparator5)
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxHumidityRandom)
+ .addComponent(chkbxHumiditySmooth))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 1, Short.MAX_VALUE))
+ .addGroup(jPanel8Layout.createSequentialGroup()
+ .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerHumidity)))
+ .addContainerGap())
+ );
+
+ jPanel3.setBackground(new java.awt.Color(207, 233, 234));
+
+ jLabel7.setText("Data Push Interval:");
+
+ spinnerInterval.setModel(new javax.swing.SpinnerNumberModel(5, 1, null, 1));
+ spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() {
+ public void stateChanged(javax.swing.event.ChangeEvent evt) {
+ spinnerIntervalStateChanged(evt);
+ }
+ });
+
+ jLabel8.setText("Seconds");
+
+ jLabel9.setText("Protocol:");
+
+ cmbProtocol.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "MQTT", "XMPP", "HTTP" }));
+ cmbProtocol.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbProtocolActionPerformed(evt);
+ }
+ });
+
+ jLabel12.setText("Interface:");
+
+ cmbInterface.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "eth0" }));
+ cmbInterface.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbInterfaceActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
+ jPanel3.setLayout(jPanel3Layout);
+ jPanel3Layout.setHorizontalGroup(
+ jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel3Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(jLabel7)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel8)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel12)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel9)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+ jPanel3Layout.setVerticalGroup(
+ jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel12)
+ .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel7)
+ .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel8)
+ .addComponent(jLabel9)
+ .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ .addContainerGap())
+ );
+
+ jPanel4.setBackground(new java.awt.Color(169, 253, 173));
+
+ chkbxEmulate.setText("Emulate data");
+ chkbxEmulate.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ chkbxEmulateActionPerformed(evt);
+ }
+ });
+
+ cmbPeriod.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " }));
+ cmbPeriod.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmbPeriodActionPerformed(evt);
+ }
+ });
+
+ jLabel1.setText("Emulation Period");
+
+ javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
+ jPanel4.setLayout(jPanel4Layout);
+ jPanel4Layout.setHorizontalGroup(
+ jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel4Layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(chkbxEmulate)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel1)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+ jPanel4Layout.setVerticalGroup(
+ jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(chkbxEmulate)
+ .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel1))
+ .addContainerGap())
+ );
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(lblAgentName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jPanel8, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(lblAgentName, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel8, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+
+ pack();
+ }// //GEN-END:initComponents
+
+ private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureRandomActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_chkbxTemperatureRandomActionPerformed
+
+ private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumidityRandomActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_chkbxHumidityRandomActionPerformed
+
+ private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerTemperatureStateChanged
+ // TODO add your handling code here:
+ }//GEN-LAST:event_spinnerTemperatureStateChanged
+
+ private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerHumidityStateChanged
+ // TODO add your handling code here:
+ }//GEN-LAST:event_spinnerHumidityStateChanged
+
+ private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMinActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtTemperatureMinActionPerformed
+
+ private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMaxActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtTemperatureMaxActionPerformed
+
+ private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMinActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtHumidityMinActionPerformed
+
+ private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMaxActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtHumidityMaxActionPerformed
+
+ private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerIntervalStateChanged
+ // TODO add your handling code here:
+ }//GEN-LAST:event_spinnerIntervalStateChanged
+
+ private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbInterfaceActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmbInterfaceActionPerformed
+
+ private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbProtocolActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmbProtocolActionPerformed
+
+ private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureSVFActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtTemperatureSVFActionPerformed
+
+ private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumiditySVFActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtHumiditySVFActionPerformed
+
+ private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureSmoothActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_chkbxTemperatureSmoothActionPerformed
+
+ private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumiditySmoothActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_chkbxHumiditySmoothActionPerformed
+
+ private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbPeriodActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmbPeriodActionPerformed
+
+ private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxEmulateActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_chkbxEmulateActionPerformed
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JCheckBox chkbxEmulate;
+ private javax.swing.JCheckBox chkbxHumidityRandom;
+ private javax.swing.JCheckBox chkbxHumiditySmooth;
+ private javax.swing.JCheckBox chkbxTemperatureRandom;
+ private javax.swing.JCheckBox chkbxTemperatureSmooth;
+ private javax.swing.JComboBox cmbInterface;
+ private javax.swing.JComboBox cmbPeriod;
+ private javax.swing.JComboBox cmbProtocol;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel10;
+ private javax.swing.JLabel jLabel11;
+ private javax.swing.JLabel jLabel12;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel20;
+ private javax.swing.JLabel jLabel23;
+ private javax.swing.JLabel jLabel24;
+ private javax.swing.JLabel jLabel25;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JLabel jLabel4;
+ private javax.swing.JLabel jLabel5;
+ private javax.swing.JLabel jLabel6;
+ private javax.swing.JLabel jLabel7;
+ private javax.swing.JLabel jLabel8;
+ private javax.swing.JLabel jLabel9;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JPanel jPanel4;
+ private javax.swing.JPanel jPanel6;
+ private javax.swing.JPanel jPanel7;
+ private javax.swing.JPanel jPanel8;
+ private javax.swing.JPanel jPanel9;
+ private javax.swing.JSeparator jSeparator1;
+ private javax.swing.JSeparator jSeparator5;
+ private javax.swing.JLabel lblAgentName;
+ private javax.swing.JLabel lblStatus;
+ private javax.swing.JPanel pnlBulbStatus;
+ private javax.swing.JSpinner spinnerHumidity;
+ private javax.swing.JSpinner spinnerInterval;
+ private javax.swing.JSpinner spinnerTemperature;
+ private javax.swing.JTextField txtHumidityMax;
+ private javax.swing.JTextField txtHumidityMin;
+ private javax.swing.JTextField txtHumiditySVF;
+ private javax.swing.JTextField txtTemperatureMax;
+ private javax.swing.JTextField txtTemperatureMin;
+ private javax.swing.JTextField txtTemperatureSVF;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml
new file mode 100644
index 000000000..5e0eafc03
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/pom.xml
@@ -0,0 +1,350 @@
+
+
+
+
+
+ virtual-fire-alarm-plugin
+ org.wso2.carbon.devicemgt-plugins
+ 6.0.16-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.api
+ war
+ WSO2 Carbon - IoT Server VirtualFireAlarm API
+ WSO2 Carbon - Virtual FireAlarm Service Management API Implementation
+ http://wso2.org
+
+
+ 2.7.18
+
+
+
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.common
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.core
+ provided
+
+
+ org.apache.axis2.wso2
+ axis2-client
+
+
+
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.certificate.mgt.core
+ provided
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxws
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxrs
+ provided
+
+
+ org.apache.cxf
+ cxf-rt-transports-http
+ provided
+
+
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ provided
+
+
+
+
+ org.apache.httpcomponents
+ httpasyncclient
+ 4.1
+ provided
+
+
+
+
+ org.codehaus.jackson
+ jackson-core-asl
+
+
+ org.codehaus.jackson
+ jackson-jaxrs
+
+
+ javax
+ javaee-web-api
+ provided
+
+
+ javax.ws.rs
+ jsr311-api
+ provided
+
+
+ commons-httpclient.wso2
+ commons-httpclient
+ provided
+
+
+
+ org.wso2.carbon
+ org.wso2.carbon.utils
+ provided
+
+
+ org.bouncycastle.wso2
+ bcprov-jdk15on
+
+
+ org.wso2.carbon
+ org.wso2.carbon.user.api
+
+
+ org.wso2.carbon
+ org.wso2.carbon.queuing
+
+
+ org.wso2.carbon
+ org.wso2.carbon.base
+
+
+ org.apache.axis2.wso2
+ axis2
+
+
+ org.igniterealtime.smack.wso2
+ smack
+
+
+ org.igniterealtime.smack.wso2
+ smackx
+
+
+ jaxen
+ jaxen
+
+
+ commons-fileupload.wso2
+ commons-fileupload
+
+
+ org.apache.ant.wso2
+ ant
+
+
+ org.apache.ant.wso2
+ ant
+
+
+ commons-httpclient.wso2
+ commons-httpclient
+
+
+ org.eclipse.equinox
+ javax.servlet
+
+
+ org.wso2.carbon
+ org.wso2.carbon.registry.api
+
+
+
+
+ commons-codec
+ commons-codec
+
+
+ org.igniterealtime.smack.wso2
+ smack
+ provided
+
+
+ org.igniterealtime.smack.wso2
+ smackx
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.identity.jwt.client.extension
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.apimgt.application.extension
+ provided
+
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.device.mgt.extensions
+ provided
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.apimgt.annotations
+ provided
+
+
+ org.springframework
+ spring-web
+ provided
+
+
+ org.apache.cxf
+ cxf-bundle
+ 3.0.0-milestone2
+ test
+
+
+ org.apache.cxf
+ cxf-bundle-jaxrs
+ provided
+ ${cxf-bundle-package.version}
+
+
+
+
+ io.swagger
+ swagger-annotations
+
+
+ io.swagger
+ swagger-core
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.wso2.orbit.com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+ io.swagger
+ swagger-jaxrs
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.wso2.orbit.com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+
+ org.json.wso2
+ json
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ provided
+
+
+ javax.ws.rs
+ jsr311-api
+ provided
+
+
+
+
+
+ maven-compiler-plugin
+
+ UTF-8
+
+ ${wso2.maven.compiler.target}
+
+
+
+ maven-war-plugin
+
+ virtual_firealarm
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-site
+ test
+
+ report
+
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+ ${basedir}/target/coverage-reports/site
+
+
+
+
+
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmService.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmService.java
new file mode 100644
index 000000000..e9a080abe
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmService.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl;
+
+import io.swagger.annotations.*;
+import org.wso2.carbon.apimgt.annotations.api.Scope;
+import org.wso2.carbon.apimgt.annotations.api.Scopes;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * This class consists the functions/APIs specific to the "actions" of the VirtualFirealarm device-type. These APIs
+ * include the ones that are used by the [Device] to contact the server (i.e: Enrollment & Publishing Data) and the
+ * ones used by the [Server/Owner] to contact the [Device] (i.e: sending control signals). This class also initializes
+ * the transport 'Connectors' [XMPP & MQTT] specific to the VirtualFirealarm device-type in order to communicate with
+ * such devices and to receive messages form it.
+ */
+@SwaggerDefinition(
+ info = @Info(
+ version = "1.0.0",
+ title = "",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = "name", value = "virtual_firealarm"),
+ @ExtensionProperty(name = "context", value = "/virtual_firealarm"),
+ })
+ }
+ ),
+ tags = {
+ @Tag(name = "virtual_firealarm,device_management", description = "")
+ }
+)
+@Scopes(
+ scopes = {
+ @Scope(
+ name = "Enroll device",
+ description = "",
+ key = "perm:firealarm:enroll",
+ permissions = {"/device-mgt/devices/enroll/firealarm"},
+ roles = {"Internal/devicemgt-user"}
+ )
+ }
+)
+public interface VirtualFireAlarmService {
+
+ String SCOPE = "scope";
+
+ /**
+ * This is an API called/used from within the Server(Front-End) or by a device Owner. It sends a control command to
+ * the VirtualFirealarm device to switch `ON` or `OFF` its buzzer. The method also takes in the protocol to be used
+ * to connect-to and send the command to the device.
+ *
+ * @param deviceId the ID of the VirtualFirealarm device on which the buzzer needs to switched `ON` or `OFF`.
+ * @param state the state to which the buzzer on the device needs to be changed. Either "ON" or "OFF".
+ * (Case-Insensitive String)
+ */
+ @POST
+ @Path("device/{deviceId}/buzz")
+ @ApiOperation(
+ consumes = MediaType.APPLICATION_JSON,
+ httpMethod = "POST",
+ value = "Switch Buzzer",
+ notes = "",
+ response = Response.class,
+ tags = "virtual_firealarm",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "perm:firealarm:enroll")
+ })
+ }
+ )
+ Response switchBuzzer(@PathParam("deviceId") String deviceId,
+ @FormParam("state") String state);
+
+ /**
+ * Retrieve Sensor data for the device type
+ */
+ @Path("device/stats/{deviceId}")
+ @GET
+ @ApiOperation(
+ consumes = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Retrieve Sensor data for the device type",
+ notes = "",
+ response = Response.class,
+ tags = "virtual_firealarm",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "perm:firealarm:enroll")
+ })
+ }
+ )
+ @Consumes("application/json")
+ @Produces("application/json")
+ Response getVirtualFirealarmStats(@PathParam("deviceId") String deviceId, @QueryParam("from") long from,
+ @QueryParam("to") long to);
+
+ @Path("device/download")
+ @GET
+ @Produces("application/zip")
+ @ApiOperation(
+ consumes = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Download agent",
+ notes = "",
+ response = Response.class,
+ tags = "virtual_firealarm",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "perm:firealarm:enroll")
+ })
+ }
+ )
+ Response downloadSketch(@QueryParam("deviceName") String deviceName, @QueryParam("sketchType") String sketchType);
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmServiceImpl.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmServiceImpl.java
new file mode 100644
index 000000000..d8f298eaf
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/VirtualFireAlarmServiceImpl.java
@@ -0,0 +1,279 @@
+/*
+* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
+import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
+import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.device.mgt.common.Device;
+import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
+import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
+import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
+import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
+import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
+import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants;
+import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
+import org.wso2.carbon.device.mgt.core.operation.mgt.ConfigOperation;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.constants.VirtualFireAlarmConstants;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dao.DeviceEventsDAO;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dao.DeviceEventsDAOImpl;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.ZipArchive;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.ZipUtil;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp.VirtualFirealarmXMPPException;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp.XmppAccount;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp.XmppConfig;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp.XmppServerClient;
+import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
+import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
+import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
+import org.wso2.carbon.user.api.UserStoreException;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.Response;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+public class VirtualFireAlarmServiceImpl implements VirtualFireAlarmService {
+
+ private static final String KEY_TYPE = "PRODUCTION";
+ private static ApiApplicationKey apiApplicationKey;
+ private static Log log = LogFactory.getLog(VirtualFireAlarmServiceImpl.class);
+
+ @POST
+ @Path("device/{deviceId}/buzz")
+ public Response switchBuzzer(@PathParam("deviceId") String deviceId, @FormParam("state") String state) {
+ if (state == null || state.isEmpty()) {
+ log.error("State is not defined for the buzzer operation");
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+ String switchToState = state.toUpperCase();
+ if (!switchToState.equals(VirtualFireAlarmConstants.STATE_ON) && !switchToState.equals(
+ VirtualFireAlarmConstants.STATE_OFF)) {
+ log.error("The requested state change shoud be either - 'ON' or 'OFF'");
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+ try {
+ if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(
+ new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE),
+ DeviceGroupConstants.Permissions.DEFAULT_OPERATOR_PERMISSIONS)) {
+ return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
+ }
+ String resource = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
+ String actualMessage = resource + ":" + switchToState;
+ String publishTopic = APIUtil.getTenantDomainOftheUser() + "/"
+ + VirtualFireAlarmConstants.DEVICE_TYPE + "/" + deviceId;
+
+ ConfigOperation commandOp = new ConfigOperation();
+ commandOp.setCode("buzz");
+ commandOp.setEnabled(true);
+ commandOp.setPayLoad(actualMessage);
+
+ Properties props = new Properties();
+ props.setProperty(VirtualFireAlarmConstants.CLIENT_JID_PROPERTY_KEY, deviceId + "@" + XmppConfig
+ .getInstance().getServerName());
+ props.setProperty(VirtualFireAlarmConstants.SUBJECT_PROPERTY_KEY, "CONTROL-REQUEST");
+ props.setProperty(VirtualFireAlarmConstants.MESSAGE_TYPE_PROPERTY_KEY,
+ VirtualFireAlarmConstants.CHAT_PROPERTY_KEY);
+ commandOp.setProperties(props);
+
+ List deviceIdentifiers = new ArrayList<>();
+ deviceIdentifiers.add(new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE));
+ APIUtil.getDeviceManagementService().addOperation(VirtualFireAlarmConstants.DEVICE_TYPE, commandOp,
+ deviceIdentifiers);
+ return Response.ok().build();
+ } catch (InvalidDeviceException e) {
+ String msg = "Error occurred while executing command operation to send keywords";
+ log.error(msg, e);
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ } catch (DeviceAccessAuthorizationException e) {
+ log.error(e.getErrorMessage(), e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+ } catch (OperationManagementException e) {
+ String msg = "Error occurred while executing command operation upon ringing the buzzer";
+ log.error(msg, e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+ }
+ }
+
+ @Path("device/stats/{deviceId}")
+ @GET
+ @Consumes("application/json")
+ @Produces("application/json")
+ public Response getVirtualFirealarmStats(@PathParam("deviceId") String deviceId, @QueryParam("from") long from,
+ @QueryParam("to") long to) {
+ try {
+ if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(
+ new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE),
+ DeviceGroupConstants.Permissions.DEFAULT_STATS_MONITOR_PERMISSIONS)) {
+ return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
+ }
+ DeviceEventsDAO eventsDAO = new DeviceEventsDAOImpl();
+ SensorRecord sensorRecord = eventsDAO.getStats(deviceId, from, to);
+ return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecord).build();
+
+ } catch (DeviceAccessAuthorizationException e) {
+ log.error(e.getErrorMessage(), e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+ }
+ }
+
+ @Path("device/download")
+ @GET
+ @Produces("application/zip")
+ public Response downloadSketch(@QueryParam("deviceName") String deviceName,
+ @QueryParam("sketchType") String sketchType) {
+ try {
+ String user = APIUtil.getAuthenticatedUser() + "@" + PrivilegedCarbonContext.getThreadLocalCarbonContext()
+ .getTenantDomain();
+ ZipArchive zipFile = createDownloadFile(user, deviceName, sketchType);
+ Response.ResponseBuilder response = Response.ok(zipFile.getZipFileContent());
+ response.status(Response.Status.OK);
+ response.type("application/zip");
+ response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\"");
+ Response resp = response.build();
+ return resp;
+ } catch (IllegalArgumentException ex) {
+ return Response.status(400).entity(ex.getMessage()).build();//bad request
+ } catch (DeviceManagementException ex) {
+ log.error(ex.getMessage(), ex);
+ return Response.status(500).entity(ex.getMessage()).build();
+ } catch (JWTClientException ex) {
+ log.error(ex.getMessage(), ex);
+ return Response.status(500).entity(ex.getMessage()).build();
+ } catch (APIManagerException ex) {
+ log.error(ex.getMessage(), ex);
+ return Response.status(500).entity(ex.getMessage()).build();
+ } catch (UserStoreException ex) {
+ log.error(ex.getMessage(), ex);
+ return Response.status(500).entity(ex.getMessage()).build();
+ } catch (VirtualFirealarmXMPPException ex) {
+ log.error(ex.getMessage(), ex);
+ return Response.status(500).entity(ex.getMessage()).build();
+ }
+ }
+
+ private boolean register(String deviceId, String name) {
+ try {
+ DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
+ deviceIdentifier.setId(deviceId);
+ deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE);
+ if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) {
+ return false;
+ }
+ Device device = new Device();
+ device.setDeviceIdentifier(deviceId);
+ EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
+ enrolmentInfo.setDateOfEnrolment(new Date().getTime());
+ enrolmentInfo.setDateOfLastUpdate(new Date().getTime());
+ enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE);
+ enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD);
+ device.setName(name);
+ device.setType(VirtualFireAlarmConstants.DEVICE_TYPE);
+ enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser());
+ device.setEnrolmentInfo(enrolmentInfo);
+ return APIUtil.getDeviceManagementService().enrollDevice(device);
+ } catch (DeviceManagementException e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType)
+ throws DeviceManagementException, APIManagerException, JWTClientException,
+ UserStoreException, VirtualFirealarmXMPPException {
+ //create new device id
+ String deviceId = shortUUID();
+ boolean status = register(deviceId, deviceName);
+ if (!status) {
+ String msg = "Error occurred while registering the device with " + "id: " + deviceId + " owner:" + owner;
+ throw new DeviceManagementException(msg);
+ }
+ if (apiApplicationKey == null) {
+ String adminUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm()
+ .getRealmConfiguration().getAdminUserName();
+ String tenantAdminDomainName = PrivilegedCarbonContext.getThreadLocalCarbonContext()
+ .getTenantDomain();
+ String applicationUsername =
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration()
+ .getAdminUserName() + "@" + PrivilegedCarbonContext.getThreadLocalCarbonContext()
+ .getTenantDomain();
+ APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
+ String[] tags = {VirtualFireAlarmConstants.DEVICE_TYPE};
+ try {
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantAdminDomainName);
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(adminUsername);
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
+
+
+ apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
+ VirtualFireAlarmConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true,
+ VirtualFireAlarmConstants.APIM_APPLICATION_TOKEN_VALIDITY_PERIOD);
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+ JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient();
+
+ String deviceType = sketchType.replace(" ", "");
+ String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
+ StringBuilder scopes = new StringBuilder("device:" + deviceType + ":" + deviceId);
+
+ // add scopes for event publishing
+ scopes.append(" perm:topic:pub:" + tenantDomain + ":" + deviceType + ":" + deviceId + ":temperature");
+
+ // add scopes for retrieve operation topic /tenantDomain/deviceType/deviceId/operation/#
+ scopes.append(" perm:topic:sub:" + tenantDomain + ":" + deviceType + ":" + deviceId + ":operation");
+
+ AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(),
+ apiApplicationKey.getConsumerSecret(), owner,
+ scopes.toString());
+
+ String accessToken = accessTokenInfo.getAccessToken();
+ String refreshToken = accessTokenInfo.getRefreshToken();
+ XmppAccount newXmppAccount = new XmppAccount();
+ newXmppAccount.setAccountName(deviceId);
+ newXmppAccount.setUsername(deviceId);
+ newXmppAccount.setPassword(accessToken);
+ newXmppAccount.setEmail(deviceId + "@" + APIUtil.getTenantDomainOftheUser());
+
+ status = XmppServerClient.createAccount(newXmppAccount);
+ if (!status) {
+ String msg = "XMPP Account was not created for device - " + deviceId + " of owner - " + owner +
+ ".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot" +
+ ".common.config.server.configs";
+ throw new DeviceManagementException(msg);
+ }
+ ZipUtil ziputil = new ZipUtil();
+ return ziputil.createZipFile(owner, sketchType, deviceId, deviceName, apiApplicationKey.toString(),
+ accessToken, refreshToken);
+ }
+
+ private static String shortUUID() {
+ UUID uuid = UUID.randomUUID();
+ long l = ByteBuffer.wrap(uuid.toString().getBytes(StandardCharsets.UTF_8)).getLong();
+ return Long.toString(l, Character.MAX_RADIX);
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/constants/VirtualFireAlarmConstants.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/constants/VirtualFireAlarmConstants.java
new file mode 100644
index 000000000..16a1bccbc
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/constants/VirtualFireAlarmConstants.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.constants;
+
+public class VirtualFireAlarmConstants {
+ public final static String DEVICE_TYPE = "virtual_firealarm";
+ public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME";
+ public final static String DEVICE_PLUGIN_DEVICE_ID = "VIRTUAL_FIREALARM_DEVICE_ID";
+ public final static String STATE_ON = "ON";
+ public final static String STATE_OFF = "OFF";
+
+ public static final String URL_PREFIX = "http://";
+ public static final String BULB_CONTEXT = "BULB";
+ public static final String POLICY_CONTEXT = "POLICY";
+
+ //sensor events sumerized table name for temperature
+// public static final String TEMPERATURE_EVENT_TABLE = "IOT_PER_DEVICE_STREAM_VIRTUALFIREALARM_TEMPERATURE";
+ public final static String DEVICE_TYPE_PROVIDER_DOMAIN = "carbon.super";
+
+ //mqtt tranport related constants
+ public static final String MQTT_ADAPTER_NAME = "virtual_firealarm_mqtt";
+ public static final String MQTT_ADAPTER_TYPE = "oauth-mqtt";
+ public static final String ADAPTER_TOPIC_PROPERTY = "topic";
+ public static final String MQTT_PORT = "\\$\\{mqtt.broker.port\\}";
+ public static final String MQTT_BROKER_HOST = "\\$\\{mqtt.broker.host\\}";
+ public static final String CARBON_CONFIG_PORT_OFFSET = "Ports.Offset";
+ public static final String DEFAULT_CARBON_LOCAL_IP_PROPERTY = "carbon.local.ip";
+ public static final int CARBON_DEFAULT_PORT_OFFSET = 0;
+ public static final int DEFAULT_MQTT_PORT = 1886;
+
+ //xmpp transport related constants
+ public static final String XMPP_ADAPTER_NAME = "virtual_firealarm_xmpp";
+ public static final String XMPP_ADAPTER_TYPE = "xmpp";
+ public static final String PASSWORD_PROPERTY_KEY = "password";
+ public static final String JID_PROPERTY_KEY = "jid";
+ public static final String CLIENT_JID_PROPERTY_KEY = "xmpp.client.jid";
+ public static final String SUBJECT_PROPERTY_KEY = "xmpp.client.subject";
+ public static final String MESSAGE_TYPE_PROPERTY_KEY = "xmpp.client.messageType";
+ public static final String CHAT_PROPERTY_KEY = "chat";
+
+ public static final String USERNAME_PROPERTY_KEY = "username";
+ public static final String DCR_PROPERTY_KEY = "dcrUrl";
+ public static final String BROKER_URL_PROPERTY_KEY = "url";
+ public static final String SCOPES_PROPERTY_KEY = "scopes";
+ public static final String QOS_PROPERTY_KEY = "qos";
+ public static final String CLIENT_ID_PROPERTY_KEY = "qos";
+ public static final String CLEAR_SESSION_PROPERTY_KEY = "clearSession";
+ public static final String TOPIC = "topic";
+ public static final String SUBSCRIBED_TOPIC = "carbon.super/virtual_firealarm/+/publisher";
+
+ public static final String CONTENT_VALIDATION = "contentValidator";
+ public static final String CONTENT_TRANSFORMATION = "contentTransformer";
+ public static final String RESOURCE = "resource";
+
+ public static final String JSON_SERIAL_KEY = "SerialNumber";
+ public static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
+ public static final String JSON_MESSAGE_KEY = "Msg";
+ public static final String JSON_SIGNATURE_KEY = "Sig";
+
+ public static final String HOST_KEY = "host";
+ public static final String PORT_KEY = "port";
+
+ public static final String SERVER_NAME = "serverName";
+
+ public static final String MQTT_ADAPTER_TOPIC_PROPERTY_NAME = "mqtt.adapter.topic";
+
+ public static final String APIM_APPLICATION_TOKEN_VALIDITY_PERIOD = "3600";
+
+ public static final String PERM_ENROLL_FIRE_ALARM = "/permission/admin/device-mgt/devices/enroll/firealarm";
+ public static final String PERM_OWNING_DEVICE_VIEW = "/permission/admin/device-mgt/devices/owning-device/view";
+
+ public static final String ROLE_NAME = "internal/devicemgt-user";
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAO.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAO.java
new file mode 100644
index 000000000..84f8a29ab
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAO.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dao;
+
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
+
+public interface DeviceEventsDAO {
+
+ SensorRecord getStats(String deviceId, long fromTime, long toTime);
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOFactory.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOFactory.java
new file mode 100644
index 000000000..5d3820bd1
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOFactory.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dao;
+
+import org.wso2.carbon.device.mgt.common.exceptions.*;
+import org.wso2.carbon.device.mgt.core.dao.util.*;
+
+public class DeviceEventsDAOFactory {
+
+ private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(DeviceEventsDAOFactory.class);
+ private static javax.sql.DataSource dataSource;
+ private static String databaseEngine;
+ private static final ThreadLocal currentConnection = new ThreadLocal<>();
+
+ public static void init(String jndiName) {
+ dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiName, null);
+ try {
+ databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
+ } catch (java.sql.SQLException e) {
+ log.error("Error occurred while retrieving config.datasource connection", e);
+ }
+ }
+
+ public static DeviceEventsDAO getDeviceEventDao() {
+ return new DeviceEventsDAOImpl();
+ }
+
+ public static void openDBConnection() throws DBConnectionException {
+ java.sql.Connection conn = currentConnection.get();
+ if (conn != null) {
+ throw new IllegalTransactionStateException("Database connection has already been obtained.");
+ }
+ try {
+ conn = dataSource.getConnection();
+ } catch (java.sql.SQLException e) {
+ throw new DBConnectionException("Failed to get a database connection.", e);
+ }
+ currentConnection.set(conn);
+ }
+
+ public static void beginTransaction() throws DBConnectionException {
+ try {
+ java.sql.Connection conn = dataSource.getConnection();
+ conn.setAutoCommit(false);
+ currentConnection.set(conn);
+ } catch (java.sql.SQLException e) {
+ throw new DBConnectionException("Error occurred while retrieving datasource connection", e);
+ }
+ }
+
+ public static java.sql.Connection getConnection() throws DBConnectionException {
+ if (currentConnection.get() == null) {
+ try {
+ currentConnection.set(dataSource.getConnection());
+ } catch (java.sql.SQLException e) {
+ throw new DBConnectionException("Error occurred while retrieving data source connection", e);
+ }
+ }
+ return currentConnection.get();
+ }
+
+ public static void commitTransaction() throws DBConnectionException {
+ try {
+ java.sql.Connection conn = currentConnection.get();
+ if (conn != null) {
+ conn.commit();
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Datasource connection associated with the current thread is null, hence commit " +
+ "has not been attempted");
+ }
+ }
+ } catch (java.sql.SQLException e) {
+ throw new DBConnectionException("Error occurred while committing the transaction", e);
+ }
+ }
+
+ public static void closeConnection() {
+ java.sql.Connection conn = currentConnection.get();
+ try {
+ if (conn != null) {
+ conn.close();
+ }
+ } catch (java.sql.SQLException e) {
+ log.error("Error occurred while close the connection");
+ }
+ currentConnection.remove();
+ }
+
+ public static void rollbackTransaction() {
+ java.sql.Connection conn = currentConnection.get();
+ if (conn == null) {
+ throw new org.wso2.carbon.device.mgt.common.exceptions.IllegalTransactionStateException("Database connection is not active. Hence, rollback is "
+ + "not attempted.");
+ }
+ try {
+ conn.rollback();
+ } catch (java.sql.SQLException e) {
+ log.warn("Error occurred while roll-backing the transaction", e);
+ }
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOImpl.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOImpl.java
new file mode 100644
index 000000000..9bbd73613
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dao/DeviceEventsDAOImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 - 2023 Entgra (Pvt) Ltd, Inc - All Rights Reserved.
+ *
+ * Unauthorised copying/redistribution of this file, via any medium is strictly prohibited.
+ *
+ * Licensed under the Entgra Commercial License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://entgra.io/licenses/entgra-commercial/1.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dao;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
+import org.wso2.carbon.device.mgt.common.exceptions.*;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+/**
+ * Implements MobileDeviceDAO for Android Devices.
+ */
+public class DeviceEventsDAOImpl implements DeviceEventsDAO {
+
+ private static final Log log = LogFactory.getLog(DeviceEventsDAOImpl.class);
+
+ @Override
+ public SensorRecord getStats(String deviceId, long fromTime, long toTime) {
+ String sql = "SELECT * FROM TABLE_VIRTUALFIREALARM_CARBONSUPER_RDBMS_PUBLISHER WHERE " +
+ "META_DEVICEID = ? AND " +
+ "META_TIME >= ? AND " +
+ "META_TIME <= ? " +
+ "ORDER BY META_TIME ASC";
+ Map stats = new LinkedHashMap<>();
+ try {
+ DeviceEventsDAOFactory.init("jdbc/EVENT_DB");
+ Connection conn = DeviceEventsDAOFactory.getConnection();
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, deviceId);
+ stmt.setLong(2, fromTime);
+ stmt.setLong(3, toTime);
+ try (ResultSet rs = stmt.executeQuery()) {
+ while (rs.next()) {
+ stats.put(rs.getLong("META_TIME"), rs.getFloat("TEMPERATURE"));
+ }
+ }
+ } catch (SQLException e) {
+ String msg = "Error occurred while retrieving device details";
+ log.error(msg);
+
+ }
+ } catch (DBConnectionException e) {
+ String msg = "Error occurred while obtaining DB connection to retrieve device details";
+ log.error(msg);
+
+ }
+// stats.entrySet()
+// .stream()
+// .sorted(Map.Entry.comparingByKey())
+// .forEach(System.out::println);
+ return new SensorRecord(stats);
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java
new file mode 100644
index 000000000..833851ea9
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/dto/SensorRecord.java
@@ -0,0 +1,33 @@
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@XmlRootElement
+/**
+ * This stores sensor event data for virtual fire alarm sense.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SensorRecord {
+
+ @XmlElementWrapper(required = true, name = "stats")
+ private Map stats;
+
+ public Map getStats() {
+ return stats;
+ }
+
+ public void setStats(Map stats) {
+ this.stats = stats;
+ }
+
+ public SensorRecord(Map stats) {
+ this.stats = stats;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/exception/VirtualFireAlarmException.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/exception/VirtualFireAlarmException.java
new file mode 100644
index 000000000..4305ec7c0
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/exception/VirtualFireAlarmException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception;
+
+public class VirtualFireAlarmException extends Exception {
+ private static final long serialVersionUID = 118512086957330189L;
+
+ public VirtualFireAlarmException(String errorMessage) {
+ super(errorMessage);
+ }
+
+ public VirtualFireAlarmException(String errorMessage, Throwable throwable) {
+ super(errorMessage, throwable);
+ }
+
+ public VirtualFireAlarmException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/listener/VirtualFireAlarmPermissionUpdateListener.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/listener/VirtualFireAlarmPermissionUpdateListener.java
new file mode 100644
index 000000000..16a6897b3
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/listener/VirtualFireAlarmPermissionUpdateListener.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.listener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.CarbonConstants;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.constants.VirtualFireAlarmConstants;
+import org.wso2.carbon.user.api.AuthorizationManager;
+import org.wso2.carbon.user.api.Permission;
+import org.wso2.carbon.user.api.UserStoreException;
+import org.wso2.carbon.user.api.UserStoreManager;
+import org.wso2.carbon.user.core.service.RealmService;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+public class VirtualFireAlarmPermissionUpdateListener implements ServletContextListener {
+
+ private static Log log = LogFactory.getLog(VirtualFireAlarmPermissionUpdateListener.class);
+ private static PrivilegedCarbonContext threadLocalCarbonContext;
+ private static RealmService realmService;
+
+ @Override
+ public void contextInitialized(ServletContextEvent servletContextEvent) {
+ threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ realmService = (RealmService) threadLocalCarbonContext.getOSGiService(RealmService.class, null);
+ UserStoreManager userStoreManager = getUserStoreManager();
+ try {
+ if (userStoreManager != null) {
+ if (!userStoreManager.isExistingRole(VirtualFireAlarmConstants.ROLE_NAME)) {
+ userStoreManager.addRole(VirtualFireAlarmConstants.ROLE_NAME, null, getPermissions());
+ } else {
+ getAuthorizationManager().authorizeRole(VirtualFireAlarmConstants.ROLE_NAME,
+ VirtualFireAlarmConstants.PERM_ENROLL_FIRE_ALARM, CarbonConstants.UI_PERMISSION_ACTION);
+ getAuthorizationManager().authorizeRole(VirtualFireAlarmConstants.ROLE_NAME,
+ VirtualFireAlarmConstants.PERM_OWNING_DEVICE_VIEW, CarbonConstants.UI_PERMISSION_ACTION);
+ }
+ }
+ } catch (UserStoreException e) {
+ log.error("Error while creating a role and adding a user for Raspberry PI.", e);
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent servletContextEvent) {
+
+ }
+
+ private UserStoreManager getUserStoreManager() {
+ UserStoreManager userStoreManager;
+ try {
+ if (realmService == null) {
+ String msg = "Realm service has not initialized.";
+ throw new IllegalStateException(msg);
+ }
+ int tenantId = threadLocalCarbonContext.getTenantId();
+ userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
+ realmService.getTenantUserRealm(tenantId).getAuthorizationManager();
+ } catch (UserStoreException e) {
+ String msg = "Error occurred while retrieving current user store manager";
+ throw new IllegalStateException(msg);
+ }
+ return userStoreManager;
+ }
+
+ private AuthorizationManager getAuthorizationManager() {
+ AuthorizationManager authorizationManager;
+ try {
+ if (realmService == null) {
+ String msg = "Realm service has not initialized.";
+ throw new IllegalStateException(msg);
+ }
+ int tenantId = threadLocalCarbonContext.getTenantId();
+ authorizationManager = realmService.getTenantUserRealm(tenantId).getAuthorizationManager();
+ } catch (UserStoreException e) {
+ String msg = "Error occurred while retrieving current user store manager";
+ throw new IllegalStateException(msg);
+ }
+ return authorizationManager;
+ }
+
+ private Permission[] getPermissions() {
+ Permission androidSense = new Permission(VirtualFireAlarmConstants.PERM_ENROLL_FIRE_ALARM,
+ CarbonConstants.UI_PERMISSION_ACTION);
+ Permission view = new Permission(VirtualFireAlarmConstants.PERM_OWNING_DEVICE_VIEW,
+ CarbonConstants.UI_PERMISSION_ACTION);
+ return new Permission[]{androidSense, view};
+ }
+}
\ No newline at end of file
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java
new file mode 100644
index 000000000..cc31583e1
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/APIUtil.java
@@ -0,0 +1,94 @@
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
+import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService;
+import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
+import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
+
+/**
+ * This class provides utility functions used by REST-API.
+ */
+public class APIUtil {
+
+ private static Log log = LogFactory.getLog(APIUtil.class);
+
+ public static String getAuthenticatedUser() {
+ PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ String username = threadLocalCarbonContext.getUsername();
+ String tenantDomain = threadLocalCarbonContext.getTenantDomain();
+ if (username.endsWith(tenantDomain)) {
+ return username.substring(0, username.lastIndexOf("@"));
+ }
+ return username;
+ }
+
+ public static DeviceManagementProviderService getDeviceManagementService() {
+ PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ DeviceManagementProviderService deviceManagementProviderService =
+ (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null);
+ if (deviceManagementProviderService == null) {
+ String msg = "Device Management service has not initialized.";
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return deviceManagementProviderService;
+ }
+
+ public static APIManagementProviderService getAPIManagementProviderService() {
+ PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ APIManagementProviderService apiManagementProviderService =
+ (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null);
+ if (apiManagementProviderService == null) {
+ String msg = "API management provider service has not initialized.";
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return apiManagementProviderService;
+ }
+
+ public static JWTClientManagerService getJWTClientManagerService() {
+ PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ JWTClientManagerService jwtClientManagerService =
+ (JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null);
+ if (jwtClientManagerService == null) {
+ String msg = "JWT Client manager service has not initialized.";
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return jwtClientManagerService;
+ }
+
+ public static String getTenantDomainOftheUser() {
+ PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ return threadLocalCarbonContext.getTenantDomain();
+ }
+
+ public static DeviceAccessAuthorizationService getDeviceAccessAuthorizationService() {
+ PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ DeviceAccessAuthorizationService deviceAccessAuthorizationService =
+ (DeviceAccessAuthorizationService) ctx.getOSGiService(DeviceAccessAuthorizationService.class, null);
+ if (deviceAccessAuthorizationService == null) {
+ String msg = "Device Authorization service has not initialized.";
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return deviceAccessAuthorizationService;
+ }
+
+ public static PlatformConfigurationManagementService getTenantConfigurationManagementService() {
+ PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ PlatformConfigurationManagementService tenantConfigurationManagementService =
+ (PlatformConfigurationManagementService) ctx.getOSGiService(PlatformConfigurationManagementService.class, null);
+ if (tenantConfigurationManagementService == null) {
+ String msg = "Tenant configuration Management service not initialized.";
+ log.error(msg);
+ throw new IllegalStateException(msg);
+ }
+ return tenantConfigurationManagementService;
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmUtilConstants.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmUtilConstants.java
new file mode 100644
index 000000000..a255b9537
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/VirtualFireAlarmUtilConstants.java
@@ -0,0 +1,25 @@
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
+
+
+public class VirtualFireAlarmUtilConstants {
+
+ public static final String TENANT_DOMAIN = "TENANT_DOMAIN";
+ public static final String DEVICE_OWNER = "DEVICE_OWNER";
+ public static final String DEVICE_ID = "DEVICE_ID";
+ public static final String DEVICE_NAME = "DEVICE_NAME";
+ public static final String HTTPS_EP = "HTTPS_EP";
+ public static final String HTTP_EP = "HTTP_EP";
+ public static final String APIM_EP = "APIM_EP";
+ public static final String MQTT_EP = "MQTT_EP";
+ public static final String XMPP_EP = "XMPP_EP";
+ public static final String VIRTUAL_FIREALARM_HTTPS_EP = "VIRTUAL_FIREALARM_HTTPS_EP";
+ public static final String VIRTUAL_FIREALARM_HTTP_EP = "VIRTUAL_FIREALARM_HTTP_EP";
+ public static final String VIRTUAL_FIREALARM_APIM_EP = "VIRTUAL_FIREALARM_APIM_EP";
+ public static final String VIRTUAL_FIREALARM_MQTT_EP = "VIRTUAL_FIREALARM_MQTT_EP";
+ public static final String VIRTUAL_FIREALARM_XMPP_EP = "VIRTUAL_FIREALARM_XMPP_EP";
+ public static final String API_APPLICATION_KEY = "API_APPLICATION_KEY";
+ public static final String DEVICE_TOKEN = "DEVICE_TOKEN";
+ public static final String DEVICE_REFRESH_TOKEN = "DEVICE_REFRESH_TOKEN";
+ public static final String SERVER_NAME = "SERVER_NAME";
+ public static final String SERVER_JID = "SERVER_JID";
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipArchive.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipArchive.java
new file mode 100644
index 000000000..2152a5e36
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipArchive.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
+
+import java.util.zip.ZipOutputStream;
+
+/**
+ * This is an utility class to hold zip files.
+ */
+public class ZipArchive {
+
+ private byte[] zipFileContent = null;
+ private String fileName = null;
+
+ public ZipArchive(String fileName, byte[] zipFile) {
+ this.fileName = fileName;
+ this.zipFileContent = zipFile;
+ }
+
+ public byte[] getZipFileContent() {
+ return zipFileContent;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipUtil.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipUtil.java
new file mode 100644
index 000000000..ed05d03c6
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/util/ZipUtil.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.JSONObject;
+import org.wso2.carbon.apimgt.application.extension.constants.ApiApplicationConstants;
+import org.wso2.carbon.core.util.Utils;
+import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
+import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
+import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
+import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
+import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp.XmppConfig;
+import org.wso2.carbon.utils.CarbonUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * This is used to create a zip file that includes the necessary configuration required for the agent.
+ */
+public class ZipUtil {
+
+ private static final Log log = LogFactory.getLog(ZipUtil.class);
+
+ private static final String LOCALHOST = "localhost";
+ private static final String HTTPS_PROTOCOL_URL = "https://${iot.gateway.host}:${iot.gateway.https.port}";
+ private static final String HTTP_PROTOCOL_URL = "http://${iot.gateway.host}:${iot.gateway.http.port}";
+ private static final String CONFIG_TYPE = "general";
+ private static final String DEFAULT_MQTT_ENDPOINT = "tcp://${mqtt.broker.host}:${mqtt.broker.port}";
+
+ public ZipArchive createZipFile(String owner, String deviceType, String deviceId, String deviceName,
+ String apiApplicationKey, String token, String refreshToken)
+ throws DeviceManagementException {
+
+ String sketchFolder = "repository" + File.separator + "resources" + File.separator + "sketches";
+ String templateSketchPath = sketchFolder + File.separator + deviceType;
+ String iotServerIP;
+
+ try {
+ iotServerIP = "127.0.0.1"; //getServerUrl();
+ String httpsServerEP = Utils.replaceSystemProperty(HTTPS_PROTOCOL_URL);
+ String httpServerEP = Utils.replaceSystemProperty(HTTP_PROTOCOL_URL);
+ String mqttEndpoint = Utils.replaceSystemProperty(DEFAULT_MQTT_ENDPOINT);
+ if (mqttEndpoint.contains(LOCALHOST)) {
+ mqttEndpoint = mqttEndpoint.replace(LOCALHOST, iotServerIP);
+ httpsServerEP = httpsServerEP.replace(LOCALHOST, iotServerIP);
+ httpServerEP = httpServerEP.replace(LOCALHOST, iotServerIP);
+ }
+
+ String xmppEndpoint = "";
+ if (XmppConfig.getInstance().isEnabled()) {
+ xmppEndpoint = XmppConfig.getInstance().getHost() + ":" + XmppConfig.getInstance().getPort();
+ if (xmppEndpoint.contains(LOCALHOST)) {
+ xmppEndpoint = xmppEndpoint.replace(LOCALHOST, iotServerIP);
+ }
+ }
+ PlatformConfiguration configuration = APIUtil.getTenantConfigurationManagementService().getConfiguration(
+ CONFIG_TYPE);
+ if (configuration != null && configuration.getConfiguration() != null && configuration
+ .getConfiguration().size() > 0) {
+ List configurations = configuration.getConfiguration();
+ for (ConfigurationEntry configurationEntry : configurations) {
+ switch (configurationEntry.getName()) {
+ case VirtualFireAlarmUtilConstants.VIRTUAL_FIREALARM_HTTPS_EP:
+ httpsServerEP = (String)configurationEntry.getValue();
+ break;
+ case VirtualFireAlarmUtilConstants.VIRTUAL_FIREALARM_HTTP_EP:
+ httpServerEP = (String)configurationEntry.getValue();
+ break;
+ case VirtualFireAlarmUtilConstants.VIRTUAL_FIREALARM_MQTT_EP:
+ mqttEndpoint = (String)configurationEntry.getValue();
+ break;
+ case VirtualFireAlarmUtilConstants.VIRTUAL_FIREALARM_XMPP_EP:
+ xmppEndpoint = (String)configurationEntry.getValue();
+ break;
+ }
+ }
+ }
+ String base64EncodedApplicationKey = getBase64EncodedAPIAppKey(apiApplicationKey).trim();
+
+ Map contextParams = new HashMap<>();
+ contextParams.put(VirtualFireAlarmUtilConstants.TENANT_DOMAIN, APIUtil.getTenantDomainOftheUser());
+ contextParams.put(VirtualFireAlarmUtilConstants.DEVICE_OWNER, owner);
+ contextParams.put(VirtualFireAlarmUtilConstants.DEVICE_ID, deviceId);
+ contextParams.put(VirtualFireAlarmUtilConstants.DEVICE_NAME, deviceName);
+ contextParams.put(VirtualFireAlarmUtilConstants.HTTPS_EP, httpsServerEP);
+ contextParams.put(VirtualFireAlarmUtilConstants.HTTP_EP, httpServerEP);
+ contextParams.put(VirtualFireAlarmUtilConstants.APIM_EP, httpServerEP);
+ contextParams.put(VirtualFireAlarmUtilConstants.MQTT_EP, mqttEndpoint);
+ contextParams.put(VirtualFireAlarmUtilConstants.XMPP_EP, "XMPP:" + xmppEndpoint);
+ contextParams.put(VirtualFireAlarmUtilConstants.API_APPLICATION_KEY, base64EncodedApplicationKey);
+ contextParams.put(VirtualFireAlarmUtilConstants.DEVICE_TOKEN, token);
+ contextParams.put(VirtualFireAlarmUtilConstants.DEVICE_REFRESH_TOKEN, refreshToken);
+ contextParams.put(VirtualFireAlarmUtilConstants.SERVER_NAME, XmppConfig.getInstance().getServerName() == null
+ ? "" : XmppConfig.getInstance().getServerName());
+ contextParams.put(VirtualFireAlarmUtilConstants.SERVER_JID, XmppConfig.getInstance().getJid() == null
+ ? "" : XmppConfig.getInstance().getJid());
+
+ ZipArchive zipFile;
+ zipFile = getSketchArchive(templateSketchPath, contextParams, deviceName);
+ return zipFile;
+ } catch (IOException e) {
+ throw new DeviceManagementException("Zip File Creation Failed", e);
+ } catch (ConfigurationManagementException e) {
+ throw new DeviceManagementException("Failed to retrieve configuration", e);
+ }
+ }
+
+ private String getBase64EncodedAPIAppKey(String apiAppCredentialsAsJSONString) {
+
+ JSONObject jsonObject = new JSONObject(apiAppCredentialsAsJSONString);
+ String consumerKey = jsonObject.get(ApiApplicationConstants.OAUTH_CLIENT_ID).toString();
+ String consumerSecret = jsonObject.get(ApiApplicationConstants.OAUTH_CLIENT_SECRET).toString();
+ String stringToEncode = consumerKey + ":" + consumerSecret;
+ return Base64.encodeBase64String(stringToEncode.getBytes());
+ }
+
+ private static String getServerUrl() {
+ try {
+ return org.apache.axis2.util.Utils.getIpAddress();
+ } catch (SocketException e) {
+ log.warn("Failed retrieving the hostname, therefore set to localhost", e);
+ return "localhost";
+ }
+ }
+
+ private ZipArchive getSketchArchive(String templateSketchPath, Map contextParams
+ , String zipFileName)
+ throws DeviceManagementException, IOException {
+ String sketchPath = CarbonUtils.getCarbonHome() + File.separator + templateSketchPath;
+ zipFileName = zipFileName + ".zip";
+ try {
+ Map> properties = getProperties(sketchPath + File.separator + "sketch" + ".properties");
+ List templateFiles = properties.get("templates");
+ List processTemplateFiles = new ArrayList<>();
+
+ for (String templateFile : templateFiles) {
+ TemplateFile tFile = new TemplateFile();
+ tFile.setContent(parseTemplate(templateSketchPath + File.separator + templateFile, contextParams));
+ tFile.setFileName(templateFile);
+ processTemplateFiles.add(tFile);
+ }
+
+ templateFiles.add("sketch.properties"); // ommit copying the props file
+
+ byte[] zip = createZipArchive(templateSketchPath, processTemplateFiles);
+ return new ZipArchive(zipFileName, zip);
+ } catch (IOException ex) {
+ throw new DeviceManagementException(
+ "Error occurred when trying to read property " + "file sketch.properties", ex);
+ }
+ }
+
+ private static Map> getProperties(String propertyFilePath) throws IOException {
+ Properties prop = new Properties();
+ InputStream input = null;
+
+ try {
+ input = new FileInputStream(propertyFilePath);
+ // load a properties file
+ prop.load(input);
+ Map> properties = new HashMap>();
+
+ String templates = prop.getProperty("templates");
+ List list = new ArrayList(Arrays.asList(templates.split(",")));
+ properties.put("templates", list);
+
+ final String filename = prop.getProperty("zipfilename");
+ list = new ArrayList() {{
+ add(filename);
+ }};
+ properties.put("zipfilename", list);
+ return properties;
+
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ log.error("Failed closing connection", e);
+ }
+ }
+ }
+ }
+
+ private static String parseTemplate(String srcFile, Map contextParams) throws IOException {
+ //read from file
+ FileInputStream inputStream = null;
+ try {
+ inputStream = new FileInputStream(srcFile);
+ String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8.toString());
+ Iterator iterator = contextParams.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry mapEntry = (Map.Entry) iterator.next();
+ content = content.replaceAll("\\$\\{" + mapEntry.getKey() + "\\}", mapEntry.getValue().toString());
+ }
+ return content;
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+
+ private static byte[] createZipArchive(String srcFolder, List processTemplateFiles) throws IOException {
+ ZipOutputStream out = null;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ out = new ZipOutputStream(new BufferedOutputStream(baos));
+ File subDir = new File(srcFolder);
+ String subdirList[] = subDir.list();
+ if (subdirList == null) {
+ log.warn("The sub directory " + subDir.getAbsolutePath() + " is empty");
+ return null;
+ }
+ for (String sd : subdirList) {
+ // get a list of files from current directory
+ File f = new File(srcFolder + File.separator + sd);
+ if (f.isDirectory()) {
+ String files[] = f.list();
+
+ if (files == null) {
+ log.warn("The current directory " + f.getAbsolutePath() + " is empty. Has no files");
+ return null;
+ }
+
+ for (int i = 0; i < files.length; i++) {
+ boolean fileAdded = false;
+ for (TemplateFile templateFile : processTemplateFiles) {
+ if (files[i].equals(templateFile.getFileName())) {
+ ZipEntry entry = new ZipEntry(templateFile.getFileName());
+ out.putNextEntry(entry);
+ out.write(templateFile.getContent().getBytes());
+ out.closeEntry();
+ fileAdded = true;
+ break;
+ } else if (f.getName().equals("sketch.properties")) {
+ fileAdded = true;
+ break;
+ }
+ }
+ if (fileAdded) {
+ continue;
+ }
+ ZipEntry entry = new ZipEntry(sd + File.separator + files[i]);
+ out.putNextEntry(entry);
+ out.write(IOUtils.toByteArray(new FileInputStream(srcFolder + File.separator + sd
+ + File.separator + files[i])));
+ out.closeEntry();
+
+ }
+ } else //it is just a file
+ {
+ boolean fileAdded = false;
+ for (TemplateFile templateFile : processTemplateFiles) {
+ if (f.getName().equals(templateFile.getFileName())) {
+ ZipEntry entry = new ZipEntry(templateFile.getFileName());
+ out.putNextEntry(entry);
+ out.write(templateFile.getContent().getBytes());
+ out.closeEntry();
+ fileAdded = true;
+ break;
+ } else if (f.getName().equals("sketch.properties")) {
+ fileAdded = true;
+ break;
+ }
+ }
+ if (fileAdded) {
+ continue;
+ }
+ ZipEntry entry = new ZipEntry(sd);
+ out.putNextEntry(entry);
+ out.write(IOUtils.toByteArray(new FileInputStream(f)));
+ out.closeEntry();
+ }
+ }
+ out.finish();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ public class TemplateFile {
+ private String content;
+ private String fileName;
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/VirtualFirealarmXMPPException.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/VirtualFirealarmXMPPException.java
new file mode 100644
index 000000000..57d0b8a0b
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/VirtualFirealarmXMPPException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp;
+
+
+public class VirtualFirealarmXMPPException extends Exception{
+
+ private String errorMessage;
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public VirtualFirealarmXMPPException(String msg, Exception nestedEx) {
+ super(msg, nestedEx);
+ setErrorMessage(msg);
+ }
+
+ public VirtualFirealarmXMPPException(String message, Throwable cause) {
+ super(message, cause);
+ setErrorMessage(message);
+ }
+
+ public VirtualFirealarmXMPPException(String msg) {
+ super(msg);
+ setErrorMessage(msg);
+ }
+
+ public VirtualFirealarmXMPPException() {
+ super();
+ }
+
+ public VirtualFirealarmXMPPException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppAccount.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppAccount.java
new file mode 100644
index 000000000..162ea957f
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppAccount.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp;
+
+/**
+ * holds the information related to account that needs to be created on xmpp server.
+ */
+public class XmppAccount {
+
+ private String username;
+ private String password;
+ private String accountName;
+ private String email;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public void setAccountName(String accountName) {
+ this.accountName = accountName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppConfig.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppConfig.java
new file mode 100644
index 000000000..d96f14c6e
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppConfig.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class XmppConfig {
+
+ private String host;
+ private int port;
+ private String username;
+ private String password;
+ private String serverName;
+ private boolean enabled;
+ private String jid;
+ private static XmppConfig xmppConfig = new XmppConfig();
+ private static final Log log = LogFactory.getLog(XmppConfig.class);
+ private static final String ENABLED = "enabled";
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+ private static final String HOST = "host";
+ private static final String PORT = "port";
+ private static final String SERVERNAME = "serverName";
+ private static final String JID = "jid";
+
+ private XmppConfig() {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ InputStream input = classLoader.getResourceAsStream("../xmpp.properties");
+ Properties properties = new Properties();
+ try {
+ properties.load(input);
+ enabled = Boolean.parseBoolean(properties.getProperty(ENABLED, "false"));
+ host = properties.getProperty(HOST);
+ port = Integer.parseInt(properties.getProperty(PORT));
+ username = properties.getProperty(USERNAME);
+ password = properties.getProperty(PASSWORD);
+ serverName = properties.getProperty(SERVERNAME);
+ jid = properties.getProperty(JID);
+ } catch (IOException e) {
+ log.error("Failed to load xmpp config properties.");
+ }
+ }
+
+ public static XmppConfig getInstance() {
+ return xmppConfig;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getJid() {
+ return jid;
+ }
+
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppServerClient.java b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppServerClient.java
new file mode 100644
index 000000000..7369f90a4
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/impl/xmpp/XmppServerClient.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.xmpp;
+
+import org.jivesoftware.smack.AccountManager;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class XmppServerClient {
+
+ public static boolean createAccount(XmppAccount xmppAccount) throws VirtualFirealarmXMPPException {
+ if (XmppConfig.getInstance().isEnabled()) {
+ if (xmppAccount != null) {
+ try {
+ ConnectionConfiguration config = new ConnectionConfiguration(XmppConfig.getInstance().getHost(),
+ XmppConfig.getInstance().getPort(),
+ "Accounts");
+ XMPPConnection xmppConnection = new XMPPConnection(config);
+ xmppConnection.connect();
+ xmppConnection.login(XmppConfig.getInstance().getUsername(), XmppConfig.getInstance().getPassword());
+ AccountManager accountManager = xmppConnection.getAccountManager();
+ Map attributes = new HashMap<>();
+ attributes.put("username", xmppAccount.getUsername());
+ attributes.put("password", xmppAccount.getPassword());
+ attributes.put("email", xmppAccount.getEmail());
+ attributes.put("name", xmppAccount.getAccountName());
+ accountManager.createAccount(xmppAccount.getUsername(), xmppAccount.getPassword(), attributes);
+ xmppConnection.disconnect();
+ return true;
+ } catch (XMPPException e) {
+ if (e.getXMPPError().getCode() == 409) {
+ //AccountAlreadyExist
+ return true;
+ } else {
+ throw new VirtualFirealarmXMPPException(
+ "XMPP account creation failed. Error: " + e.getLocalizedMessage(), e);
+ }
+ }
+ } else {
+ throw new VirtualFirealarmXMPPException("Invalid XMPP attributes");
+ }
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/permissions.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/permissions.xml
new file mode 100644
index 000000000..fbad43f95
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/permissions.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+ Download device
+ /device-mgt/user/devices
+ /device/download
+ GET
+ virtual_firealarm_user
+
+
+ Control Buzz
+ /device-mgt/user/operation
+ /device/*/buzz
+ POST
+ virtual_firealarm_user
+
+
+ Get Stats
+ /device-mgt/user/stats
+ /device/stats/*
+ GET
+ virtual_firealarm_user
+
+
\ No newline at end of file
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/webapp-classloading.xml
new file mode 100644
index 000000000..7fc571bef
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/META-INF/webapp-classloading.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+ false
+
+
+ CXF3,Carbon
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/cxf-servlet.xml
new file mode 100644
index 000000000..37a69c268
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/cxf-servlet.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/web.xml b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..ff13bc494
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,38 @@
+
+
+ WSO2 IoT Server
+ WSO2 IoT Server
+
+
+ CXFServlet
+ org.apache.cxf.transport.servlet.CXFServlet
+ 1
+
+
+ CXFServlet
+ /*
+
+
+ doAuthentication
+ true
+
+
+ isSharedWithAllTenants
+ true
+
+
+
+
+ managed-api-enabled
+ true
+
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.listener.VirtualFireAlarmPermissionUpdateListener
+
+
+
\ No newline at end of file
diff --git a/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/xmpp.properties b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/xmpp.properties
new file mode 100644
index 000000000..3a173cb92
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.api/src/main/webapp/WEB-INF/xmpp.properties
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#[XMPP-Configurations]
+enabled=false
+username=admin
+password=admin
+host=localhost
+port=5222
+serverName=localhost
+jid=admin@localhost
\ No newline at end of file
diff --git a/components/device-types/virtual-fire-alarm-plugin/pom.xml b/components/device-types/virtual-fire-alarm-plugin/pom.xml
new file mode 100644
index 000000000..086689116
--- /dev/null
+++ b/components/device-types/virtual-fire-alarm-plugin/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ device-types
+ 6.0.16-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ virtual-fire-alarm-plugin
+ pom
+ WSO2 Carbon - Virtual Fire Alarm Plugin
+ http://wso2.org
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.api
+
+
+
+
+
+
+ org.apache.felix
+ maven-scr-plugin
+ 1.7.2
+
+
+ generate-scr-scrdescriptor
+
+ scr
+
+
+
+
+
+
+
+
diff --git a/components/extensions/cdmf-transport-adapters/input/org.wso2.carbon.device.mgt.input.adapter.mqtt/src/main/java/org/wso2/carbon/device/mgt/input/adapter/mqtt/util/MQTTAdapterListener.java b/components/extensions/cdmf-transport-adapters/input/org.wso2.carbon.device.mgt.input.adapter.mqtt/src/main/java/org/wso2/carbon/device/mgt/input/adapter/mqtt/util/MQTTAdapterListener.java
index 5ae262b9a..ad1c149b7 100644
--- a/components/extensions/cdmf-transport-adapters/input/org.wso2.carbon.device.mgt.input.adapter.mqtt/src/main/java/org/wso2/carbon/device/mgt/input/adapter/mqtt/util/MQTTAdapterListener.java
+++ b/components/extensions/cdmf-transport-adapters/input/org.wso2.carbon.device.mgt.input.adapter.mqtt/src/main/java/org/wso2/carbon/device/mgt/input/adapter/mqtt/util/MQTTAdapterListener.java
@@ -199,7 +199,7 @@ public class MQTTAdapterListener implements MqttCallback, Runnable {
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
try {
String mqttMsgString = mqttMessage.toString();
- String msgText = mqttMsgString.substring(mqttMsgString.indexOf("{"), mqttMsgString.indexOf("}") +1);
+ String msgText = mqttMsgString.substring(mqttMsgString.indexOf("{"), mqttMsgString.lastIndexOf("}") + 1);
if (log.isDebugEnabled()) {
log.debug(msgText);
}
diff --git a/components/extensions/emqx-extensions/io.entgra.device.mgt.plugins.emqx.exhook/src/main/java/io/entgra/device/mgt/plugins/emqx/exhook/ExServer.java b/components/extensions/emqx-extensions/io.entgra.device.mgt.plugins.emqx.exhook/src/main/java/io/entgra/device/mgt/plugins/emqx/exhook/ExServer.java
index 51da55a64..1951a7bfa 100644
--- a/components/extensions/emqx-extensions/io.entgra.device.mgt.plugins.emqx.exhook/src/main/java/io/entgra/device/mgt/plugins/emqx/exhook/ExServer.java
+++ b/components/extensions/emqx-extensions/io.entgra.device.mgt.plugins.emqx.exhook/src/main/java/io/entgra/device/mgt/plugins/emqx/exhook/ExServer.java
@@ -467,8 +467,8 @@ public class ExServer {
String deviceType = null;
String deviceId = null;
for (String scope : scopeArray) {
- if (scope.startsWith("device_")) {
- String[] scopeParts = scope.split("_");
+ if (scope.startsWith("device:")) {
+ String[] scopeParts = scope.split(":");
deviceType = scopeParts[1];
deviceId = scopeParts[2];
break;
diff --git a/features/device-types-feature/pom.xml b/features/device-types-feature/pom.xml
new file mode 100644
index 000000000..80dee946e
--- /dev/null
+++ b/features/device-types-feature/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ carbon-device-mgt-plugins-parent
+ 6.0.16-SNAPSHOT
+ ../../pom.xml
+
+
+ 4.0.0
+ device-types-feature
+ pom
+ WSO2 Carbon - Device Management IoT Plugins Feature
+ http://wso2.org
+
+
+ virtual-fire-alarm-plugin-feature
+
+
+
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/pom.xml b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/pom.xml
new file mode 100644
index 000000000..12b505e63
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/pom.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ virtual-fire-alarm-plugin-feature
+ 6.0.16-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature
+ pom
+ WSO2 Carbon - IoT Server VirtualFireAlarm Backend Feature
+ http://wso2.org
+ This feature contains the VirtualFireAlarm Device type specific backend implementations for the IoT Server
+
+
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.api
+ ${carbon.devicemgt.plugins.version}
+ war
+
+
+ org.wso2.orbit.com.h2database
+ h2
+ ${orbit.h2.version}
+
+
+
+
+
+
+ maven-resources-plugin
+
+
+ copy-resources
+ generate-resources
+
+ copy-resources
+
+
+ src/main/resources
+
+
+ resources
+
+ build.properties
+ p2.inf
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+
+ copy-jaxrs-war
+ package
+
+ copy
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.api
+
+ war
+ true
+ ${project.build.directory}/maven-shared-archive-resources/webapps/
+ virtual_firealarm.war
+
+
+
+
+
+ copy-agent-jar
+ package
+
+ copy
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl
+
+ true
+ ${project.build.directory}/maven-shared-archive-resources/agent/
+ wso2-firealarm-virtual-agent.jar
+
+
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+ ${carbon.p2.plugin.version}
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend
+ ../../../features/etc/feature.properties
+
+
+ org.wso2.carbon.p2.category.type:server
+ org.eclipse.equinox.p2.type.group:true
+
+
+
+
+
+
+
+
+
+
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/deviceConfig.properties b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/deviceConfig.properties
new file mode 100644
index 000000000..80bee115a
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/deviceConfig.properties
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#[Device-Configurations]
+tenantDomain=${TENANT_DOMAIN}
+owner=${DEVICE_OWNER}
+deviceId=${DEVICE_ID}
+device-name=${DEVICE_NAME}
+https-ep=${HTTPS_EP}
+http-ep=${HTTP_EP}
+apim-ep=${APIM_EP}
+mqtt-ep=${MQTT_EP}
+xmpp-ep=${XMPP_EP}
+application-key=${API_APPLICATION_KEY}
+auth-token=${DEVICE_TOKEN}
+refresh-token=${DEVICE_REFRESH_TOKEN}
+push-interval=15
+xmpp-server-name=${SERVER_NAME}
+server-jid=${SERVER_JID}
+
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/sketch.properties b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/sketch.properties
new file mode 100644
index 000000000..801bd88de
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/sketch.properties
@@ -0,0 +1,2 @@
+templates=deviceConfig.properties
+zipfilename=FireAlarmVirtualAgent.zip
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.bat b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.bat
new file mode 100755
index 000000000..f19520f14
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.bat
@@ -0,0 +1,7 @@
+@echo off
+echo.
+echo.WSO2 IOT Sample
+echo.Virtual Fire Alarm
+echo.initializing agent
+echo.
+java -jar wso2-firealarm-virtual-agent.jar
\ No newline at end of file
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.sh b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.sh
new file mode 100755
index 000000000..37853c9b1
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/agent/start-device.sh
@@ -0,0 +1,190 @@
+#!/bin/bash
+
+echo "----------------------------------------------------------------"
+echo "| WSO2 IOT Sample "
+echo "| Virtual RaspiAlarm "
+echo "| ---------------- "
+echo "| ....initializing startup-script "
+echo "----------------------------------------------------------------"
+
+#while true; do
+# read -p "What is the network-interface of your device that the Agent should use (find from ifconfig. ex: wlan0,en0,eth0..) > " interface
+#
+# echo "Setting the network-interface to " $interface
+# sed s/^network-interface=.*/network-interface=$interface/ deviceConfig.properties > myTmp
+# mv -f myTmp deviceConfig.properties
+# break;
+#done
+#
+#while true; do
+# read -p "Whats the time-interval (in seconds) between successive Data-Pushes to the WSO2-IoT-Server (ex: '60' indicates 1 minute) > " interval
+#
+# if [ $interval -eq $interval 2>/dev/null ]
+# then
+# echo "Setting data-push interval to " $interval " seconds."
+# sed s/^push-interval=.*/push-interval=$interval/ deviceConfig.properties > myTmp
+# mv -f myTmp deviceConfig.properties
+# break;
+# else
+# echo "Input needs to be an integer indicating the number seconds between successive data-pushes."
+# fi
+#done
+
+
+java -jar wso2-firealarm-virtual-agent.jar
+
+#while true; do
+# read -p "Do you wish to run 'apt-get update' and continue? [Yes/No] " yn
+# case $yn in
+# [Yy]* ) sudo apt-get update;
+# break;;
+# [Nn]* ) echo "Continuing without apt-get update...";
+# break;;
+# * ) echo "Please answer yes or no.";
+# esac
+#done
+#
+#if [ $? -ne 0 ]; then
+# echo "apt-get update failed.... Some dependencies may not get installed"
+# echo "If an already installed version of the package exists, try running:"
+# echo "----------------------------------------------------------------"
+# echo "sudo -i"
+# echo "cd /var/lib/dpkg/info"
+# echo "rm -rf wso2-raspi-alarm*"
+# echo "dpkg --remove --force-remove-reinstreq wso2-raspi-alarm"
+# echo "exit"
+# echo "----------------------------------------------------------------"
+# echo "Retry Installation...."
+# break;
+#fi
+#
+#echo "Installing 'gdebi' package..."
+#sudo apt-get install gdebi # installation of gdebi
+#
+#
+#if [ $? -ne 0 ]; then
+# echo "gdebi installation failed.... dependencies will not be installed without gdebi"
+# read -p "Do you wish to continue without gdebi? [Yes/No] " yn
+# case $yn in
+# [Yy]* ) echo "Continueing without gdebi.....";;
+# [Nn]* ) echo "Try to resolve errors and re-run the script.";
+# exit;;
+# * ) exit;;
+# esac
+#fi
+#
+#
+#for f in ./wso2-raspi-alarm_1.0_armhf.deb; do
+# ## Check if the glob gets expanded to existing files.
+# ## If not, f here will be exactly the pattern above
+# ## and the exists test will evaluate to false.
+# # [ -e "$f" ] && echo "'wso2-raspi-alarm_1.0_armhf.deb' file found and installing" || echo "'wso2-raspi-alarm_1.0_armhf.deb' file does not exist in current path"; exit;
+# if [ -e "$f" ]; then
+# echo "'wso2-raspi-alarm_1.0_armhf.deb' file found and installing now...."
+# else
+# echo "'wso2-raspi-alarm_1.0_armhf.deb' file does not exist in current path. \nExiting installation...";
+# exit;
+# fi
+# ## This is all we needed to know, so we can break after the first iteration
+# break
+#done
+#
+#echo "Installing the 'wso2-raspi-alarm deb package'"
+#sudo gdebi wso2-raspi-alarm_1.0_armhf.deb
+#
+#if [ $? -ne 0 ]; then
+# echo "Installation Failed...."
+# exit;
+#fi
+
+#sudo killall -9 python
+#
+#for f in ./RaspberryAgent.zip; do
+# ## Check if the glob gets expanded to existing files.
+# ## If not, f here will be exactly the pattern above
+# ## and the exists test will evaluate to false.
+# # [ -e "$f" ] && echo "'wso2-raspi-alarm_1.0_armhf.deb' file found and installing" || echo "'wso2-raspi-alarm_1.0_armhf.deb' file does not exist in current path"; exit;
+# if [ -e "$f" ]; then
+# echo "Agent files found......"
+# sudo rm -rf /usr/local/src/RaspberryAgent
+# sudo unzip RaspberryAgent.zip -d /usr/local/src/
+# else
+# echo "'RaspberryAgent.zip' file does not exist in current path. \nInstalling without upgrading agent...";
+# fi
+# ## This is all we needed to know, so we can break after the first iteration
+# break
+#done
+#
+#for f in /usr/local/src/RaspberryAgent/rc.local; do
+# ## Check if the glob gets expanded to existing files.
+# ## If not, f here will be exactly the pattern above
+# ## and the exists test will evaluate to false.
+# if [ -e "$f" ]; then
+# echo "Copying boot script"
+# sudo mv /usr/local/src/RaspberryAgent/rc.local /etc/rc.local
+# sudo chmod +x /etc/rc.local
+# else
+# echo "Unable to set agent statup on boot";
+# fi
+# ## This is all we needed to know, so we can break after the first iteration
+# break
+#done
+#
+#for f in ./deviceConfigs.cfg; do
+# ## Check if the glob gets expanded to existing files.
+# ## If not, f here will be exactly the pattern above
+# ## and the exists test will evaluate to false.
+# if [ -e "$f" ]; then
+# echo "Configuration file found......"
+# else
+# echo "'deviceConfigs.cfg' file does not exist in current path. \nExiting installation...";
+# exit;
+# fi
+# ## This is all we needed to know, so we can break after the first iteration
+# break
+#done
+#
+#echo "Altering Configuration file"
+#sed -i 's|[/,]||g' deviceConfigs.cfg
+#
+#echo "Copying configurations file to /usr/local/src/RaspberryAgent"
+#sudo cp ./deviceConfigs.cfg /usr/local/src/RaspberryAgent/
+#
+#if [ $? -ne 0 ]; then
+# echo "Copying configuration file failed...."
+# exit;
+#fi
+#
+#while true; do
+# read -p "Whats the time-interval (in seconds) between successive Data-Pushes to the WSO2-DC (ex: '60' indicates 1 minute) > " input
+#
+# if [ $input -eq $input 2>/dev/null ]
+# then
+# echo "Setting data-push interval to $input seconds."
+# echo $input > /usr/local/src/RaspberryAgent/time-interval
+# break;
+# else
+# echo "Input needs to be an integer indicating the number seconds between successive data-pushes."
+# fi
+#done
+#
+#cd /usr/local/src/RaspberryAgent/
+#sudo chmod +x RaspberryStats.py
+#sudo nohup ./RaspberryStats.py -i $input
+
+
+
+
+
+ Control buzzer
+ Control buzzer on Virtual Firealarm
+
+
+
+
+
+
+ true
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ en_US
+ 1.0.0
+ This is license text
+
+
+
\ No newline at end of file
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/p2.inf b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/p2.inf
new file mode 100644
index 000000000..1656f09da
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/p2.inf
@@ -0,0 +1,16 @@
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../../repository/deployment/server/webapps/);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/webapps/,target:${installFolder}/../../../repository/deployment/server/webapps/,overwrite:true);\
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../../repository/deployment/server/devicetypes/);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/devicetypes/,target:${installFolder}/../../../repository/deployment/server/devicetypes/,overwrite:true);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/receiver/,target:${installFolder}/../../../repository/deployment/server/eventreceivers/,overwrite:true);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/streams/,target:${installFolder}/../../../repository/deployment/server/eventstreams/,overwrite:true);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/publisher/,target:${installFolder}/../../../repository/deployment/server/eventpublishers/,overwrite:true);\
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../../repository/resources/sketches/);\
+org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../../repository/resources/sketches/virtual_firealarm/);\
+org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend_${feature.version}/agent/,target:${installFolder}/../../../repository/resources/sketches/virtual_firealarm/,overwrite:true);\
+
+instructions.unconfigure = \
+org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../repository/deployment/server/webapps/virtual_firealarm.war);\
+org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../repository/deployment/server/webapps/virtual_firealarm);\
+org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../repository/deployment/server/devicetypes/virtual_firealarm.xml);\
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/publisher/virtual_firealam_rdbms_publisher-carbon.super.xml b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/publisher/virtual_firealam_rdbms_publisher-carbon.super.xml
new file mode 100644
index 000000000..39cd6d4cf
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/publisher/virtual_firealam_rdbms_publisher-carbon.super.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ EVENT_DB
+ table_virtualfirealarm_carbonsuper_rdbms_publisher
+ insert
+
+
+
+
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/receiver/virtualfirealarm_receiver.xml b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/receiver/virtualfirealarm_receiver.xml
new file mode 100644
index 000000000..1deea34dd
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/receiver/virtualfirealarm_receiver.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+ carbon.super/virtual_firealarm/+/temperature
+ default
+ true
+
+
+
+
+
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/streams/iot.per.device.stream.virtualfirealarm_1.0.0.json b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/streams/iot.per.device.stream.virtualfirealarm_1.0.0.json
new file mode 100644
index 000000000..751c13824
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature/src/main/resources/streams/iot.per.device.stream.virtualfirealarm_1.0.0.json
@@ -0,0 +1,16 @@
+{
+ "name": "iot.per.device.stream.virtualfirealarm",
+ "version": "1.0.0",
+ "nickName": "virtual_firealarm",
+ "description": "Temperature data received from the virtual_firealarm",
+ "metaData": [
+ {"name":"owner","type":"STRING"},
+ {"name":"deviceId","type":"STRING"},
+ {"name":"time","type":"TIMESTAMP"}
+ ],
+ "payloadData": [
+ {
+ "name": "temperature","type": "FLOAT"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/features/device-types-feature/virtual-fire-alarm-plugin-feature/pom.xml b/features/device-types-feature/virtual-fire-alarm-plugin-feature/pom.xml
new file mode 100644
index 000000000..81b17d129
--- /dev/null
+++ b/features/device-types-feature/virtual-fire-alarm-plugin-feature/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ device-types-feature
+ 6.0.16-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ virtual-fire-alarm-plugin-feature
+ pom
+ WSO2 Carbon - IoT Server VirtualFireAlarm Device Feature
+ http://wso2.org
+
+
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.backend.feature
+
+
+
diff --git a/pom.xml b/pom.xml
index 196acd4f5..aabd1f6c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,10 +37,12 @@
components/extensions
components/mobile-plugins
+ components/device-types
features/analytics-feature
features/mobile-plugins-feature
features/extensions-feature
+ features/device-types-feature
@@ -491,6 +493,16 @@
org.wso2.carbon.device.mgt.mobile.android.api
${carbon.devicemgt.plugins.version}
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.api
+ ${carbon.devicemgt.plugins.version}
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl
+ ${carbon.devicemgt.plugins.version}
+