com.digi.wva.internal.Hardware.java Source code

Java tutorial

Introduction

Here is the source code for com.digi.wva.internal.Hardware.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
 * the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2014 Digi International Inc., All Rights Reserved.
 */

package com.digi.wva.internal;

import android.util.Log;

import com.digi.wva.async.WvaCallback;
import com.digi.wva.util.WvaUtil;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/** This class allows interaction with hardware components of the WVA gateway itself rather than
 * the vehicle to which it is attached. These are located under the {@code hw} web services tree.
 */
public class Hardware {
    private static final DateTimeFormatter format = ISODateTimeFormat.dateTimeNoMillis();
    private static final String TAG = "wvalib Hardware";
    private static final String LED_BASE = "hw/leds/";
    private static final String BUTTON_BASE = "hw/buttons/";
    private static final String TIME_BASE = "hw/time/";
    private static final String LED_KEY = "leds";
    private static final String BUTTON_KEY = "buttons";

    private final HttpClient httpClient;
    private final Set<String> leds, buttons;

    /**
     * Constructor.
     * @param httpClient the HTTP client used to handle HTTP calls made
     */
    public Hardware(HttpClient httpClient) {
        this.httpClient = httpClient;
        // Make the LED and button name caches the equivalent to a ConcurrentHashSet
        this.leds = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
        this.buttons = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
    }

    /**
     * The necessary callbacks for fetchLedNames and fetchButtonNames are
     * practically identical, so we create a new subclass of HttpCallback
     * to handle both in a more generic manner.
     */
    private class NameCacheInitializingCallback extends HttpClient.HttpCallback {
        private final String key;
        private final Set<String> initSet;
        private final WvaCallback<Set<String>> callback;

        public NameCacheInitializingCallback(String key, Set<String> initSet, WvaCallback<Set<String>> callback) {
            this.key = key;
            this.initSet = initSet;
            this.callback = callback;
        }

        @Override
        public void onSuccess(JSONObject response) {
            if (!response.has(this.key)) {
                String message = String.format("Couldn't initialize hardware. JSON response has no %s key",
                        this.key);
                Log.w(TAG, message);
                callback.onResponse(new JSONException(message), null);
                return;
            }

            try {
                JSONArray uris = response.getJSONArray(key);
                int l = uris.length();
                String uri;
                for (int i = 0; i < l; i++) {
                    uri = uris.getString(i);
                    String name = WvaUtil.getEndpointFromUri(uri);
                    initSet.add(name);
                    Log.v(TAG, String.format("adding hardware %s", name));
                }

                callback.onResponse(null, new HashSet<String>(initSet));
            } catch (JSONException e) {
                Log.w(TAG, String.format("Couldn't initialize %s correctly", this.key), e);
                callback.onResponse(e, null);
            }
        }

        @Override
        public void onFailure(Throwable error) {
            Log.w(TAG, String.format("Received error while initializing hardware %s", this.key), error);
            callback.onResponse(error, null);
        }
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#fetchLedNames(WvaCallback)}
     */
    public void fetchLedNames(WvaCallback<Set<String>> callback) {
        httpClient.get(LED_BASE, new NameCacheInitializingCallback(LED_KEY, leds, callback));
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#fetchButtonNames(WvaCallback)}
     */
    public void fetchButtonNames(WvaCallback<Set<String>> callback) {
        httpClient.get(BUTTON_BASE, new NameCacheInitializingCallback(BUTTON_KEY, buttons, callback));
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#getCachedButtonNames()}
     */
    public Set<String> getCachedButtonNames() {
        return new HashSet<String>(buttons);
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#getCachedLedNames()}
     */
    public Set<String> getCachedLedNames() {
        return new HashSet<String>(leds);
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#fetchButtonState(String, WvaCallback)}
     */
    public void fetchButtonState(final String buttonName, final WvaCallback<Boolean> cb) {
        httpClient.get(BUTTON_BASE + buttonName, new HttpClient.HttpCallback() {
            @Override
            public void onSuccess(JSONObject btn) {
                String pressed;
                try {
                    pressed = btn.getString("button");
                    boolean upDown = pressed.equals("up");
                    cb.onResponse(null, upDown);

                } catch (JSONException e) {
                    Log.w(TAG, "unable to fetch " + buttonName);
                    cb.onResponse(e, null);
                }
            }

            @Override
            public void onFailure(Throwable error) {
                cb.onResponse(error, null);
            }
        });
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#fetchLedState(String, WvaCallback)}
     */
    public void fetchLedState(final String ledName, final WvaCallback<Boolean> cb) {
        httpClient.get(LED_BASE + ledName, new HttpClient.HttpCallback() {
            @Override
            public void onSuccess(JSONObject led) {
                String state;
                try {
                    state = led.getString("led");
                    boolean onOff = state.equals("on");
                    cb.onResponse(null, onOff);
                } catch (JSONException e) {
                    Log.w(TAG, "unable to fetch " + ledName);
                    cb.onResponse(e, null);
                }

            }

            @Override
            public void onFailure(Throwable error) {
                cb.onResponse(error, null);
            }
        });
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#setLedState(String, boolean, WvaCallback)}
     * @throws JSONException if an error occurs while creating the request
     */
    public void setLedState(final String ledName, final boolean state, final WvaCallback<Boolean> cb)
            throws JSONException {
        JSONObject led = new JSONObject();
        led.put("led", state ? "on" : "off");

        httpClient.put(LED_BASE + ledName, led, new HttpClient.ExpectEmptyCallback() {
            @Override
            public void onSuccess() {
                if (cb != null)
                    cb.onResponse(null, state);
            }

            @Override
            public void onBodyNotEmpty(String body) {
                Log.e(TAG, "setLedState got unexpected response body content:\n" + body);
                onFailure(new Exception("Unexpected response body: " + body));
            }

            @Override
            public void onFailure(Throwable error) {
                Log.e(TAG, "Failed to set state of LED " + ledName, error);
                if (cb != null) {
                    cb.onResponse(error, null);
                }
            }
        });

    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#fetchTime(WvaCallback)}
     */
    public void fetchTime(final WvaCallback<DateTime> cb) {
        httpClient.get(TIME_BASE, new HttpClient.HttpCallback() {
            @Override
            public void onSuccess(JSONObject timeObj) {
                String timeStr;
                try {
                    timeStr = timeObj.getString("time");
                    cb.onResponse(null, format.parseDateTime(timeStr));
                } catch (JSONException e) {
                    Log.w(TAG, "unable to get time.");
                    cb.onResponse(e, null);
                }
            }

            @Override
            public void onFailure(Throwable error) {
                cb.onResponse(error, null);
            }
        });
    }

    /**
     * Underlying implementation of {@link com.digi.wva.WVA#setTime(DateTime, WvaCallback)}
     *
     * @throws JSONException if an error occurs while creating the request
     */
    public void setTime(final DateTime newTime, final WvaCallback<DateTime> cb) throws JSONException {
        JSONObject time = new JSONObject();

        final DateTime newTimeUTC = newTime.toDateTime(DateTimeZone.UTC);

        final String timestamp = format.print(newTimeUTC);
        Log.i(TAG, "Sending timestamp down: " + timestamp);
        time.put("time", timestamp);

        httpClient.put(TIME_BASE, time, new HttpClient.ExpectEmptyCallback() {
            @Override
            public void onSuccess() {
                if (cb != null) {
                    cb.onResponse(null, newTimeUTC);
                }
            }

            @Override
            public void onBodyNotEmpty(String body) {
                Log.e(TAG, "setTime got unexpected response body content:\n" + body);
                onFailure(new Exception("Unexpected response body: " + body));
            }

            @Override
            public void onFailure(Throwable error) {
                Log.e(TAG, "Failed to set WVA device time to " + timestamp, error);
                if (cb != null) {
                    cb.onResponse(error, newTimeUTC);
                }
            }
        });
    }
}