com.ibm.iotf.sample.client.application.ApplicationFirmwareRequestSample.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.iotf.sample.client.application.ApplicationFirmwareRequestSample.java

Source

/**
 *****************************************************************************
 * Copyright (c) 2015 IBM Corporation and other Contributors.
    
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Sathiskumar Palaniappan - Initial Contribution
 *****************************************************************************
 */
package com.ibm.iotf.sample.client.application;

import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
import java.util.ArrayList;

import com.cloudant.client.api.*; // .CloudantClient;
import com.cloudant.client.api.model.ChangesResult;
import com.cloudant.client.api.model.ChangesResult.Row;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import com.ibm.iotf.client.IoTFCReSTException;
import com.ibm.iotf.client.api.APIClient;
import com.ibm.iotf.devicemgmt.device.ManagedDevice;

/**
 * This sample showcases various ReST operations that can be performed on Watson IoT Platform to
 * initiate/get/delete one or more device management operations.
 */
public class ApplicationFirmwareRequestSample {

    private final static String PROPERTIES_FILE_NAME = "/application.properties";

    // Define a sequence to help obtaining the change set
    private String firmwareDBSequence;
    private Database firmwareDB;
    private String username = null;
    private String password = null;
    private String documentId = null;
    private String attachmentName = null;
    private String deviceFwVersion = "1.0.2";
    private String dbName;
    private String deviceType;
    private String deviceId;

    // document Id containing the latest firmware image
    private String currentFirmware = "iot_1.0-2_armhf.deb";
    private static String latestFirmware;
    private String latestFirmwareVersion;

    private static URL url = null;

    ManagedDevice dmClient;

    protected final static JsonParser JSON_PARSER = new JsonParser();

    private APIClient apiClient = null;

    public ApplicationFirmwareRequestSample() {
        /**
          * Load device properties
          */
        Properties props = new Properties();
        try {
            props.load(ApplicationFirmwareRequestSample.class.getResourceAsStream(PROPERTIES_FILE_NAME));
        } catch (IOException e1) {
            System.err.println("Not able to read the properties file, exiting..");
            System.exit(-1);
        }

        deviceType = trimedValue(props.getProperty("Device-Type"));
        deviceId = trimedValue(props.getProperty("Device-ID"));
        username = trimedValue(props.getProperty("User-Name"));
        password = trimedValue(props.getProperty("Password"));
        dbName = trimedValue(props.getProperty("Repository-DB"));

        try {
            //Instantiate the class by passing the properties file
            this.apiClient = new APIClient(props);

            StringBuilder sb = new StringBuilder();
            sb.append("https://").append(username).append(":").append(password).append("@").append(username)
                    .append(".cloudant.com");

            System.out.println(sb);

            CloudantClient client = new CloudantClient(sb.toString(), username, password);

            System.out.println("Connected to Cloudant");
            System.out.println("Server Version: " + client.serverVersion());

            firmwareDB = client.database(dbName, false);
            System.out.println("Value of Cloudant DB is " + firmwareDB);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    public static void main(String[] args) throws IoTFCReSTException {

        ApplicationFirmwareRequestSample sample = new ApplicationFirmwareRequestSample();
        sample.getDeviceFwVersion();
        while (true) {
            try {
                // Check on Cloudant DB to see if any latest firmware is available
                // If yes, then, Initiate Firmware Download, else, wait and check again after SLEEP time elapses
                if (sample.checkIfNewFirmwareImage()) {
                    if (sample.initiateFirmwareDownloadRequest()) {
                        // Wait for the Download to complete and receive an acknowledgement from the Device
                        sample.waitForRequestToFinish();
                        // Once the acknowledgement on the completion of Firmware Donwload comes in, initiate Firmware Update
                        if (sample.initiateFirmwareUpdateRequest()) {
                            // Wait for the Firmware Update action to complete and receive an acknowledgement from the Device
                            sample.waitForRequestToFinish();
                            // call getDeviceFwVersion to get the latest firmware version details from the device
                            sample.getDeviceFwVersion();
                        }
                    }
                }
                // SLEEP for the defined time, if the Cloudant DB has the Firmware of same version, as available on the Device
                Thread.sleep(1000 * 60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * The following method helps initiated Device Management Request
     * Firmware Update, being triggered from Application and initiated 
     * through Watson IoT Platform
     * @return
     */
    private boolean initiateFirmwareUpdateRequest() {

        try {
            clearAllDMRequests();
        } catch (IoTFCReSTException e1) {
            System.out.println("Cleared all the Device Management Requests, to start clean");
            e1.printStackTrace();
        }

        // Prepare the Device Action as Firmware Update
        String updateRequest = "{\"action\": \"firmware/update\", \"devices\": [{\"typeId\": \"" + deviceType
                + "\",\"deviceId\": \"" + deviceId + "\"}]}";

        JsonObject update = (JsonObject) new JsonParser().parse(updateRequest);
        System.out.println(update);
        boolean response = false;
        try {
            response = apiClient.initiateDeviceManagementRequest(update);
        } catch (IoTFCReSTException e) {
            e.printStackTrace();
        }
        System.out.println(response);

        return response;

    }

    private void clearAllDMRequests() throws IoTFCReSTException {
        JsonElement response = this.apiClient.getAllDeviceManagementRequests();
        if (response.getAsJsonObject().get("results") != null) {
            JsonArray requests = response.getAsJsonObject().get("results").getAsJsonArray();
            for (int i = 0; i < requests.size(); i++) {
                JsonElement request = requests.get(i);
                String requestId = request.getAsJsonObject().get("id").getAsString();
                this.apiClient.deleteDeviceManagementRequest(requestId);
            }
        }

    }

    /**
     * The following method showcases steps to construct the URL to download the
     * latest Firmware from the Cloudant NoSQL DB and helps create the Device Management
     * request 'Firmware Download'.
     * @return
     */
    public boolean initiateFirmwareDownloadRequest() {
        try {
            clearAllDMRequests();
        } catch (IoTFCReSTException e1) {
            System.out.println("Cleared all the Device Management Requests, to start clean");
            e1.printStackTrace();
        }

        // Construct the URL to download the Debian Package from the Cloudant NoSQL DB 
        String buildURL = ("https://" + username + ".cloudant.com/" + dbName + "/" + documentId + "/"
                + attachmentName);

        try {
            System.out.println("Building the URL ...");
            url = new URL(buildURL);
            System.out.println("Value of url is " + url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        // Prepare the Device Action as Firmware Download, passing the constructed URL

        String downloadRequest = "{\"action\": \"firmware/download\", \"parameters\": ["
                + "{\"name\": \"version\", \"value\": \"" + latestFirmwareVersion + "\" },"
                + "{\"name\": \"name\", \"value\": \"" + attachmentName + "\"},"
                + "{\"name\": \"uri\",\"value\": \"" + url + "\"}" + "],\"devices\": [{\"typeId\": \"" + deviceType
                + "\",\"deviceId\": \"" + deviceId + "\"}]}";

        JsonObject download = (JsonObject) new JsonParser().parse(downloadRequest);
        System.out.println(download);
        boolean response = false;
        try {

            response = apiClient.initiateDeviceManagementRequest(download);
        } catch (IoTFCReSTException e) {
            e.printStackTrace();
        }
        System.out.println(response);

        return response;

    }

    /**
     * The following method sends an acknowledgement from Device to Application,
     * mentioning the status of the execution of Device Action, as triggered
     * by the Application through Watson IoT Platform
     * @throws IoTFCReSTException
     */
    private void waitForRequestToFinish() throws IoTFCReSTException {
        JsonElement response = this.apiClient.getAllDeviceManagementRequests();
        JsonArray requests = response.getAsJsonObject().get("results").getAsJsonArray();
        JsonElement request = requests.get(0);
        String requestId = request.getAsJsonObject().get("id").getAsString();

        int count = 0;
        while (count++ <= 3600) { // wait for an hour, before giving it up
            JsonObject details = this.apiClient.getDeviceManagementRequest(requestId);
            System.out.println(details);
            if (details.get("complete").getAsBoolean() == true) {
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static String trimedValue(String value) {
        if (value == null || value == "") {
            return "";
        } else {
            return value.trim();
        }
    }

    /**
     * The following method snoops the Cloudant NoSQL DB to see, if there's a newer version
     * of Firmware, whose version is greater than that of the Firmware, that is currently
     * active on the Device. If yes, it triggers Firmware Download action. Else, it waits
     * till the Sleep time elapses and does the check again.
     * @return
     */
    public boolean checkIfNewFirmwareImage() {

        ChangesResult changes = null;
        if (this.firmwareDBSequence == null) {
            changes = firmwareDB.changes().includeDocs(true).getChanges();
        } else {
            changes = firmwareDB.changes().includeDocs(true).since(firmwareDBSequence).getChanges();
        }
        firmwareDBSequence = firmwareDB.info().getUpdateSeq();
        String version = deviceFwVersion;
        boolean firmwareAvailable = false;
        if (changes.getResults().size() != 0) {
            List<ChangesResult.Row> rows = changes.getResults();

            for (Row row : rows) {
                JsonObject attachment = row.getDoc();

                if (attachment != null) {

                    if (attachment.get("_deleted") != null && attachment.get("_deleted").getAsBoolean() == true) {
                        continue;
                    }

                    if (attachment.get("version") != null && attachment.get("_attachments") != null) {
                        System.out.println(attachment);
                        String retrievedVersion = attachment.get("version").getAsString();
                        System.out.println(retrievedVersion);
                        if (isVersionGreater(version, retrievedVersion)) {
                            firmwareAvailable = true;
                            String docId = row.getId();
                            documentId = docId.toString();
                            //                   // System.out.println("Value of docId is " +docId);
                            latestFirmwareVersion = retrievedVersion;
                            version = retrievedVersion;

                            JsonObject obj = attachment.get("_attachments").getAsJsonObject();
                            Set<Entry<String, JsonElement>> entrySet = obj.entrySet();

                            Iterator<Entry<String, JsonElement>> itr = entrySet.iterator();
                            if (itr.hasNext()) {
                                Entry<String, JsonElement> entry = itr.next();
                                setLatestFirmware(entry.getKey());
                                attachmentName = entry.getKey();
                                System.out.println("Setting latest firmware to " + entry.getKey());
                                // attachmentName = entry.getKey().toString();
                            }
                        }
                    }
                }
            }
        }
        return firmwareAvailable;
    }

    /**
     * This method checks whether the retrieved version is higher than
     * the deviceVersion.
     */
    private static boolean isVersionGreater(String deviceVersion, String retrievedVersion) {
        String[] retrieved = retrievedVersion.split("\\.");
        String[] device = deviceVersion.split("\\.");
        try {
            for (int i = 0; i < device.length; i++) {
                int retInt = Integer.parseInt(retrieved[i]);
                int deviceInt = Integer.parseInt(device[i]);
                if (retInt > deviceInt) {
                    return true;
                }
            }
        } catch (Exception e) {
        }
        return false;
    }

    protected String getCurrentFirmware() {
        return currentFirmware;
    }

    protected void setCurrentFirmware(String currentFirmware) {
        this.currentFirmware = currentFirmware;
    }

    protected static String getLatestFirmware() {
        return latestFirmware;
    }

    protected void setLatestFirmware(String latestFirmware) {
        ApplicationFirmwareRequestSample.latestFirmware = latestFirmware;
    }

    /**
     * This sample showcases how to get device details using the Java Client Library.
     * @throws IoTFCReSTException
     */
    private void getDeviceFwVersion() throws IoTFCReSTException {
        try {

            Properties props = new Properties();
            try {
                props.load(ApplicationFirmwareRequestSample.class.getResourceAsStream(PROPERTIES_FILE_NAME));
            } catch (IOException e1) {
                System.err.println("Not able to read the properties file, exiting..");
                System.exit(-1);
            }

            String deviceID = trimedValue(props.getProperty("Device-ID"));
            String deviceType = trimedValue(props.getProperty("Device-Type"));

            System.out.println("get device --> " + deviceID);
            JsonObject response = this.apiClient.getDevice(deviceType, deviceID);

            // JsonElement 

            if (response.get("deviceInfo") != null) {
                JsonObject deviceInfo = response.get("deviceInfo").getAsJsonObject();
                System.out.println(deviceInfo);
                if (deviceInfo.get("fwVersion") != null) {
                    deviceFwVersion = deviceInfo.get("fwVersion").getAsString();
                }
            } else {
                System.out.println("Device Info is Null, Considering the default criteria!");
            }
            System.out.println(response);
        } catch (IoTFCReSTException e) {
            System.out.println("HttpCode :" + e.getHttpCode() + " ErrorMessage :: " + e.getMessage());
            // Print if there is a partial response
            System.out.println(e.getResponse());
        }
    }
}