com.ibm.internal.iotf.devicemgmt.handler.DeviceUpdateRequestHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.internal.iotf.devicemgmt.handler.DeviceUpdateRequestHandler.java

Source

/**
 *****************************************************************************
 Copyright (c) 2015-16 IBM Corporation and other Contributors.
 All rights reserved. This program and the accompanying materials
 are made available under the terms of the Eclipse Public License v1.0
 which accompanies this distribution, and is available at
 http://www.eclipse.org/legal/epl-v10.html
 Contributors:
 Mike Tran - Initial Contribution
 Sathiskumar Palaniappan - Added resource model to update based on resource
 *****************************************************************************
 *
 */
package com.ibm.internal.iotf.devicemgmt.handler;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.ibm.internal.iotf.devicemgmt.ManagedClient;
import com.ibm.internal.iotf.devicemgmt.DMServerTopic;
import com.ibm.internal.iotf.devicemgmt.ResponseCode;
import com.ibm.iotf.devicemgmt.resource.Resource;
import com.ibm.iotf.util.LoggerUtility;

/**
 * 
 * <br>Update device attributes
 * <br>Watson IoT Platform can send this request to a device to update values of one or more device attributes. 
 * Supported update targets are location, metadata, device information and firmware.
 * <p>Topic
 *   <li>iotdm-1/device/update
 * <br><br>Message format
 * <br>Request:
 * <br>{
 * <br>  "d": {
 * <br>      "value": { }
 * <br>  },
 * <br>  "reqId": "string"
 * <br>}
 * <br><br>"value" is the new value of the device attribute. 
 * <br>It is a complex field matching the device model. 
 * <br>Only writeable fields should be updated as a result of this operation.
 * <br>Values can be updated in:
 *   <li>location      (see Update location section for details)
 *   <li>metadata      (Optional)
 *   <li>deviceInfo      (Optional)
 *   <li>mgmt.firmware   (see Firmware update process for details)
 * <br><br>Response:
 * <br>{
 *    <br>"rc": number,
 *    <br>"message": "string",
 *    <br>"d": {
 *       <br>"fields": [
 *          <br> "string"
 *       <br>]
 *   <br>},
 *   <br>"reqId": "string"
 * <br>}
 * <br><br>"message" field can be specified if "rc" is not 200.
 * <br>If any field value could not be retrieved, 
 * <br>"rc" should be set to 404 (if not found) or 500 (any other reason). 
 * <br>"fields" array should contain the name of each field that could not be updated.
 *
 */
public class DeviceUpdateRequestHandler extends DMRequestHandler {
    private static final String CLASS_NAME = DeviceUpdateRequestHandler.class.getName();

    private static final ExecutorService executor = Executors.newCachedThreadPool();

    public DeviceUpdateRequestHandler(ManagedClient dmClient) {
        setDMClient(dmClient);
    }

    /**
     * Subscribe to update topic
     */
    @Override
    protected void subscribe() {
        DMServerTopic topic = this.getDMClient().getDMServerTopic();
        subscribe(topic.getDeviceUpdateTopic());
    }

    /**
     * Returns the update topic
     */
    @Override
    protected String getTopic() {
        DMServerTopic topic = this.getDMClient().getDMServerTopic();
        return topic.getDeviceUpdateTopic();
    }

    /**
     * Unsubscribe update topic
     */
    @Override
    protected void unsubscribe() {
        DMServerTopic topic = this.getDMClient().getDMServerTopic();
        unsubscribe(topic.getDeviceUpdateTopic());
    }

    /**
     * This method handles all the update requests from IBM Watson IoT Platform
     */
    @Override
    public void handleRequest(JsonObject jsonRequest) {
        final String METHOD = "handleRequest";
        List<Resource> fireRequiredResources = new ArrayList<Resource>();
        JsonArray fields = null;
        ResponseCode rc = ResponseCode.DM_UPDATE_SUCCESS;
        JsonObject response = new JsonObject();
        JsonObject d = (JsonObject) jsonRequest.get("d");

        if (d != null) {
            fields = (JsonArray) d.get("fields");
            if (fields != null) {

                /**
                 * update the fields in actual device object
                 */
                JsonArray resFields = new JsonArray();
                for (int i = 0; i < fields.size(); i++) {
                    JsonObject obj = (JsonObject) fields.get(i);
                    if (obj.get("field") != null) {
                        String key = obj.get("field").getAsString();
                        JsonObject value = (JsonObject) obj.get("value");
                        boolean success = false;
                        try {
                            Resource resource = getDMClient().getDeviceData().getResource(key);
                            if (resource != null) {
                                success = updateField(resource, value);
                                fireRequiredResources.add(resource);
                            }
                        } catch (Exception e) {
                            LoggerUtility.log(Level.SEVERE, CLASS_NAME, METHOD,
                                    "Exception in updating field " + key + " value " + value, e);

                            if (e.getMessage() != null)
                                response.add("message", new JsonPrimitive(e.getMessage()));
                        }
                        if (success == false) {
                            resFields.add(new JsonPrimitive(key));
                            rc = ResponseCode.DM_NOT_FOUND;
                        }
                    }
                }

                if (resFields.size() != 0) {
                    JsonObject json = new JsonObject();
                    json.add("fields", resFields);
                    response.add("d", json);
                }
            }
        }

        response.add("rc", new JsonPrimitive(rc.getCode()));
        response.add("reqId", jsonRequest.get("reqId"));
        respond(response);

        // Lets fire the property change event now - this will notify the
        // device code if they are listening to
        Task task = this.new Task(fireRequiredResources);
        executor.execute(task);
    }

    /**
     * Update resource with new value
     * 
     * @param resource resource to be updated
     * @param value - the new value
     * @return - true if the update is successful, false if not
     */
    private boolean updateField(Resource resource, JsonObject value) {
        if (resource != null) {
            // Update the properties but do not fire the change event
            resource.update(value, false);
            return true;
        }
        return false;
    }

    /**
     * A task that fires the modified event on all the
     * resources that are updated
     */
    private class Task implements Runnable {
        private List<Resource> fireRequiredResources;

        private Task(List<Resource> fireRequiredResources) {
            this.fireRequiredResources = fireRequiredResources;
        }

        @Override
        public void run() {
            for (int i = 0; i < fireRequiredResources.size(); i++) {
                Resource resource = fireRequiredResources.get(i);
                resource.notifyExternalListeners();
            }
        }

    }
}