@PUT
 @Path("device/{deviceId}/policy")
 public Response updatePolicy(
     @PathParam("deviceId") String deviceId,
     @QueryParam("protocol") String protocol,
     @FormParam("policy") String policy) {
   String protocolString = protocol.toUpperCase();
   if (log.isDebugEnabled()) {
     log.debug(
         "Sending request to update-policy of device [" + deviceId + "] via " + protocolString);
   }
   try {
     if (!APIUtil.getDeviceAccessAuthorizationService()
         .isUserAuthorized(
             new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE),
             DeviceGroupConstants.Permissions.DEFAULT_MANAGE_POLICIES_PERMISSIONS)) {
       return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
     }
     PrivateKey serverPrivateKey = VirtualFirealarmSecurityManager.getServerPrivateKey();
     String actualMessage = VirtualFireAlarmConstants.POLICY_CONTEXT + ":" + policy;
     String encryptedMsg =
         VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, serverPrivateKey);
     Map<String, String> dynamicProperties = new HashMap<>();
     switch (protocolString) {
       case XMPP_PROTOCOL:
         dynamicProperties.put(
             VirtualFireAlarmConstants.JID_PROPERTY_KEY,
             deviceId + "@" + XmppConfig.getInstance().getServerName());
         dynamicProperties.put(VirtualFireAlarmConstants.SUBJECT_PROPERTY_KEY, "POLICTY-REQUEST");
         dynamicProperties.put(
             VirtualFireAlarmConstants.MESSAGE_TYPE_PROPERTY_KEY,
             VirtualFireAlarmConstants.CHAT_PROPERTY_KEY);
         APIUtil.getOutputEventAdapterService()
             .publish(
                 VirtualFireAlarmConstants.XMPP_ADAPTER_NAME, dynamicProperties, encryptedMsg);
         break;
       default:
         String publishTopic =
             APIUtil.getTenantDomainOftheUser()
                 + "/"
                 + VirtualFireAlarmConstants.DEVICE_TYPE
                 + "/"
                 + deviceId;
         dynamicProperties.put(VirtualFireAlarmConstants.ADAPTER_TOPIC_PROPERTY, publishTopic);
         APIUtil.getOutputEventAdapterService()
             .publish(
                 VirtualFireAlarmConstants.MQTT_ADAPTER_NAME, dynamicProperties, encryptedMsg);
         break;
     }
     return Response.ok().build();
   } catch (DeviceAccessAuthorizationException e) {
     log.error(e.getErrorMessage(), e);
     return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
   } catch (VirtualFireAlarmException e) {
     log.error(e);
     return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
   }
 }
  /**
   * {@inheritDoc} VirtualFirealarm device-type specific implementation to publish data to the
   * device. This method calls the {@link #publishToQueue(String, MqttMessage)} method of the
   * "MQTTTransportHandler" class.
   */
  @Override
  public void publishDeviceData(String... publishData) throws TransportHandlerException {
    if (publishData.length != 4) {
      String errorMsg =
          "Incorrect number of arguments received to SEND-MQTT Message. "
              + "Need to be [owner, deviceId, resource{BULB/TEMP}, state{ON/OFF or null}]";
      log.error(errorMsg);
      throw new TransportHandlerException(errorMsg);
    }

    String deviceOwner = publishData[0];
    String deviceId = publishData[1];
    String resource = publishData[2];
    String state = publishData[3];

    MqttMessage pushMessage = new MqttMessage();
    String publishTopic = "wso2/" + VirtualFireAlarmConstants.DEVICE_TYPE + "/" + deviceId;

    try {
      PublicKey devicePublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
      PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();

      String actualMessage = resource + ":" + state;
      String encryptedMsg =
          VirtualFireAlarmServiceUtils.prepareSecurePayLoad(
              actualMessage, devicePublicKey, serverPrivateKey);

      pushMessage.setPayload(encryptedMsg.getBytes(StandardCharsets.UTF_8));
      pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE);
      pushMessage.setRetained(false);

      publishToQueue(publishTopic, pushMessage);

    } catch (VirtualFireAlarmException e) {
      String errorMsg =
          "Preparing Secure payload failed for device - ["
              + deviceId
              + "] of owner - "
              + "["
              + deviceOwner
              + "].";
      log.error(errorMsg);
      throw new TransportHandlerException(errorMsg, e);
    }
  }
  /**
   * {@inheritDoc} VirtualFirealarm device-type specific implementation to process incoming
   * messages. This is the specific method signature of the overloaded "processIncomingMessage"
   * method that gets called from the messageArrived() callback of the "MQTTTransportHandler".
   */
  @Override
  public void processIncomingMessage(MqttMessage mqttMessage, String... messageParams) {
    if (messageParams.length != 0) {
      // owner and the deviceId are extracted from the MQTT topic to which the message was received.
      // <Topic> = [ServerName/Owner/DeviceType/DeviceId/"publisher"]
      String topic = messageParams[0];
      String[] topicParams = topic.split("/");
      String deviceId = topicParams[2];
      if (log.isDebugEnabled()) {
        log.debug("Received MQTT message for: [DEVICE.ID-" + deviceId + "]");
      }

      String actualMessage;
      try {
        // the hash-code of the deviceId is used as the alias for device certificates during SCEP
        // enrollment.
        // hence, the same is used here to fetch the device-specific-certificate from the key store.
        PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
        PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();

        // the MQTT-messages from VirtualFireAlarm devices are in the form {"Msg":<MESSAGE>,
        // "Sig":<SIGNATURE>}
        actualMessage =
            VirtualFireAlarmServiceUtils.extractMessageFromPayload(
                mqttMessage.toString(), serverPrivateKey, clientPublicKey);
        if (log.isDebugEnabled()) {
          log.debug("MQTT: Received Message [" + actualMessage + "] topic: [" + topic + "]");
        }

        if (actualMessage.contains("PUBLISHER")) {
          float temperature = Float.parseFloat(actualMessage.split(":")[2]);
          try {
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            DeviceManagementProviderService deviceManagementProviderService =
                (DeviceManagementProviderService)
                    ctx.getOSGiService(DeviceManagementProviderService.class, null);
            if (deviceManagementProviderService != null) {
              DeviceIdentifier identifier =
                  new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE);
              Device device = deviceManagementProviderService.getDevice(identifier);
              if (device != null) {
                String owner = device.getEnrolmentInfo().getOwner();
                ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true);
                ctx.setUsername(owner);
                if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) {
                  log.error("MQTT Subscriber: Publishing data to DAS failed.");
                }
              }
            }
          } catch (DeviceManagementException e) {
            log.error(
                "Failed to retreive the device managment service for device type "
                    + VirtualFireAlarmConstants.DEVICE_TYPE,
                e);
          } finally {
            PrivilegedCarbonContext.endTenantFlow();
          }
          if (log.isDebugEnabled()) {
            log.debug("MQTT Subscriber: Published data to DAS successfully.");
          }

        } else if (actualMessage.contains("TEMPERATURE")) {
          String temperatureValue = actualMessage.split(":")[1];
        }
      } catch (VirtualFireAlarmException e) {
        String errorMsg =
            "CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful.";
        log.error(errorMsg, e);
      }
    } else {
      String errorMsg =
          "MQTT message ["
              + mqttMessage.toString()
              + "] was received without the topic information.";
      log.warn(errorMsg);
    }
  }
  @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("/", "");
      PrivateKey serverPrivateKey = VirtualFirealarmSecurityManager.getServerPrivateKey();
      String actualMessage = resource + ":" + switchToState;
      String encryptedMsg =
          VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, serverPrivateKey);
      String publishTopic =
          APIUtil.getTenantDomainOftheUser()
              + "/"
              + VirtualFireAlarmConstants.DEVICE_TYPE
              + "/"
              + deviceId;

      Operation commandOp = new CommandOperation();
      commandOp.setCode("buzz");
      commandOp.setType(Operation.Type.COMMAND);
      commandOp.setEnabled(true);
      commandOp.setPayLoad(encryptedMsg);

      Properties props = new Properties();
      props.setProperty(VirtualFireAlarmConstants.MQTT_ADAPTER_TOPIC_PROPERTY_NAME, publishTopic);
      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<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
      deviceIdentifiers.add(new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE));
      APIUtil.getDeviceManagementService()
          .addOperation(VirtualFireAlarmConstants.DEVICE_TYPE, commandOp, deviceIdentifiers);
      return Response.ok().build();
    } catch (DeviceAccessAuthorizationException e) {
      log.error(e.getErrorMessage(), e);
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
    } catch (VirtualFireAlarmException e) {
      String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "]";
      log.error(errorMsg);
      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();
    }
  }