br.org.cesar.knot.lib.connection.ThingApi.java Source code

Java tutorial

Introduction

Here is the source code for br.org.cesar.knot.lib.connection.ThingApi.java

Source

/*
 * Copyright (c) 2017, CESAR.
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license. See the LICENSE file for details.
 *
 *
 */

package br.org.cesar.knot.lib.connection;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import java.net.HttpURLConnection;
import java.util.List;

import br.org.cesar.knot.lib.event.Event;
import br.org.cesar.knot.lib.exception.InvalidDeviceOwnerStateException;
import br.org.cesar.knot.lib.exception.KnotException;
import br.org.cesar.knot.lib.model.AbstractDeviceOwner;
import br.org.cesar.knot.lib.model.AbstractThingData;
import br.org.cesar.knot.lib.model.AbstractThingDevice;
import br.org.cesar.knot.lib.model.AbstractThingMessage;
import br.org.cesar.knot.lib.model.KnotList;
import br.org.cesar.knot.lib.model.KnotQueryData;
import br.org.cesar.knot.lib.util.DateUtils;

/**
 * The main class that list all method available to use with KNOT
 */
final class ThingApi {

    public static final String EMPTY_ARRAY = "[]";
    private static final String EMPTY_JSON = "{}";
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final String HEADER_AUTH_UUID = "meshblu_auth_uuid";
    private static final String HEADER_AUTH_TOKEN = "meshblu_auth_token";
    private static final String DATA_PATH = "/data/";
    private static final String DEVICE_PATH = "/devices/";
    private static final String DEVICE_PROPERTY_PATH_GATEWAY = "/gateway/";
    private static final String CLAIM_DEVICES_PATH = "/claimdevice/";
    private static final String WHOAMI = "/v2/whoami/";
    private static final String MY_DEVICES_PATH = "/mydevices/";
    private static final String MESSAGE = "/messages/";
    private static final String JSON_DEVICES = "devices";
    private static final String JSON_DATA = "data";

    /**
     * Tag used to build the date query
     */
    private static String DATE_START = "start";

    /**
     * Tag used to build the date query
     */
    private static String DATE_FINISH = "finish";

    /**
     * Tag used to build the date query
     */
    private static String LIMIT = "limit";

    private static String EQUAL = "=";

    private static ThingApi sInstance;
    private final Handler mMainHandler;
    private final OkHttpClient mHttpClient;
    private final Gson mGson;
    private final String mEndPoint;
    private AbstractDeviceOwner abstractDeviceOwner;

    public ThingApi(String endPoint, String owner_uuid, String owner_token) {
        mMainHandler = new Handler(Looper.getMainLooper());
        mHttpClient = new OkHttpClient();
        mGson = new Gson();
        mEndPoint = endPoint;

        abstractDeviceOwner = new AbstractDeviceOwner();
        abstractDeviceOwner.setUuid(owner_uuid);
        abstractDeviceOwner.setToken(owner_token);
    }

    /**
     * Release the current reference of DeviceOwner
     */
    public void releaseDeviceOwner() {
        this.abstractDeviceOwner = null;
    }

    /**
     * Generate a new Device in Meshblu instance
     *
     * @param device model sample to create a new one. Basically this device model
     *               contains attributes that will be saved into Meshblu.
     *               Please note that uuid and token will always
     *               be generated by Meshblu (please see AbstractThingDevice).
     *               It is important set the custom attribute for your classes
     * @return New device with meshblu token and uuid values
     * @throws KnotException KnotException
     * @see AbstractThingDevice
     */
    public <T extends AbstractThingDevice> T createDevice(T device) throws KnotException {
        final String endPoint = mEndPoint + DEVICE_PATH;
        device.owner = abstractDeviceOwner.getUuid();
        String json = mGson.toJson(device);
        RequestBody body = createRequestBodyWith(json);
        Request request = generateBasicRequestBuild(endPoint).post(body).build();

        try {
            Response response = mHttpClient.newCall(request).execute();

            // Retrieve the result of web service
            final T responseData = (T) mGson.fromJson(response.body().string(), device.getClass());

            //Return the data sent by web server
            return responseData;
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #createDevice(AbstractThingDevice)}
     *
     * @param device   model sample to create a new one. Basically this device model
     *                 contains attributes that will be saved into Meshblu.
     *                 Please note that uuid and token will always
     *                 be generated by Meshblu (please see AbstractThingDevice).
     *                 It is important set the custom attribute for your classes
     * @param callback Callback for this method
     * @see AbstractThingDevice
     */
    public <T extends AbstractThingDevice> void createDevice(final T device, final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = createDevice(device);
                    dispatchSuccess(callback, result);
                } catch (final KnotException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Turns the device belongs to someone. When a device is created in
     * Meshblu, it is an orphan device. In other words, everyone can made any
     * changes on this device. After claim a device, only the
     * owner can delete or update it.
     * Note: In Meshblu, the owner for one device IS another device.
     *
     * @param device the identifier of device (uuid)
     * @return a boolean value to indicate if the device could be claimed
     * @throws KnotException KnotException
     */
    public Boolean claimDevice(String device) throws InvalidDeviceOwnerStateException, KnotException {
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("the device owner is null or invalid");
        }

        // Create a request to claim the given device
        final String endPoint = mEndPoint + CLAIM_DEVICES_PATH + device;
        RequestBody body = createEmptyRequestBody();
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).put(body).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            return response.code() == HttpURLConnection.HTTP_OK;
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #claimDevice(String)}
     *
     * @param device   the identifier of device (uuid)
     * @param callback Callback for this method
     */
    public void claimDevice(final String device, final Event<Boolean> callback) {
        // If exists a valid owner than do a request to claim the given device
        new Thread() {
            @Override
            public void run() {
                try {
                    Boolean result = claimDevice(device);
                    dispatchSuccess(callback, result);
                } catch (InvalidDeviceOwnerStateException | KnotException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Update an existent device
     *
     * @param device the identifier of device (uuid)
     * @return the object updated
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> T updateDevice(String id, T device)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }
        // Update the given device
        final String endPoint = mEndPoint + DEVICE_PATH + id;
        String json = mGson.toJson(device);
        RequestBody body = createRequestBodyWith(json);
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).put(body).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            return (T) mGson.fromJson(response.body().string(), device.getClass());
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #updateDevice(String, AbstractThingDevice)}
     *
     * @param device   the identifier of device (uuid)
     * @param callback Callback for this method
     */
    public <T extends AbstractThingDevice> void updateDevice(final String id, final T device,
            final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = updateDevice(id, device);
                    dispatchSuccess(callback, result);
                } catch (InvalidDeviceOwnerStateException | KnotException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Delete a device from Meshblu instance. If the device is an orphan one,
     * anyone can delete it. However if the device has an owner,
     * only it can execute this action.
     *
     * @param device the device identifier (uuid)
     * @return a boolean to indicate if the device was deleted
     * @throws KnotException KnotException
     */
    public boolean deleteDevice(String device) throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // delete the given device
        final String endPoint = mEndPoint + DEVICE_PATH + device;
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).delete().build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            return response.code() == HttpURLConnection.HTTP_OK;
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link ThingApi#deleteDevice(String)}
     *
     * @param device   the device identifier (uuid)
     * @param callback Callback for this method
     */
    public void deleteDevice(final String device, final Event<Boolean> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    Boolean result = deleteDevice(device);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Get all information regarding the device.
     *
     * @param clazz The class for this device. Meshblu works with any type of objects and
     *              it is necessary deserialize the return to a valid object.
     *              Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @return an json element containing device informations
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> T whoAmI(Class<T> clazz)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // Get all information regarding the given device
        final String endPoint = mEndPoint + WHOAMI;
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            JsonElement jsonElement = new JsonParser().parse(response.body().string());
            return mGson.fromJson(jsonElement.toString(), clazz);
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #whoAmI(Class)}
     *
     * @param clazz    The class for this device. Meshblu works with any type of objects and
     *                 it is necessary deserialize the return to a valid object.
     *                 Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @param callback Callback for this method
     * @return an object based on the class parameter
     */

    public <T extends AbstractThingDevice> void whoAmI(final Class<T> clazz, final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = whoAmI(clazz);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Get a specific device from Meshblu instance.
     *
     * @param device the device identifier (uuid)
     * @param clazz  The class for this device. Meshblu works with any type of objects and
     *               it is necessary deserialize the return to a valid object.
     *               Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @return an object based on the class parameter
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> T getDevice(String device, Class<T> clazz)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // Get the specific device from meshblue instance
        final String endPoint = mEndPoint + DEVICE_PATH + device;
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            JsonElement jsonElement = new JsonParser().parse(response.body().string());
            JsonArray jsonArray = jsonElement.getAsJsonObject().getAsJsonArray(JSON_DEVICES);
            if (jsonArray.size() == 0) {
                return null;
            }
            return mGson.fromJson(jsonArray.get(0).toString(), clazz);
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #getDevice(String, Class)}
     *
     * @param device   the device identifier (uuid)
     * @param clazz    The class for this device. Meshblu works with any type of objects and
     *                 it is necessary deserialize the return to a valid object.
     *                 Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @param callback Callback for this method
     * @return an object based on the class parameter
     */
    public <T extends AbstractThingDevice> void getDevice(final String device, final Class<T> clazz,
            final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = getDevice(device, clazz);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Get a specific device's gateway from Meshblu instance.
     *
     * @param device the device identifier (uuid)
     * @param clazz  The class for this device. Meshblu works with any type of objects and
     *               it is necessary deserialize the return to a valid object.
     *               Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @return an object based on the class parameter
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> T getDeviceGateway(String device, Class<T> clazz)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // Get a specific device's gateway from Meshblu instance.
        final String endPoint = mEndPoint + DEVICE_PATH + device + DEVICE_PROPERTY_PATH_GATEWAY;
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            JsonElement jsonElement = new JsonParser().parse(response.body().string());
            JsonArray jsonArray = jsonElement.getAsJsonObject().getAsJsonArray(JSON_DEVICES);
            if (jsonArray.size() == 0) {
                return null;
            }
            return mGson.fromJson(jsonArray.get(0).toString(), clazz);
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #getDeviceGateway(String, Class)}
     *
     * @param device   the device identifier (uuid)
     * @param clazz    The class for this device. Meshblu works with any type of objects and
     *                 it is necessary deserialize the return to a valid object.
     *                 Note: The class parameter should be a extension of {@link AbstractThingDevice}
     * @param callback Callback for this method
     * @return an object based on the class parameter
     */
    public <T extends AbstractThingDevice> void getDeviceGateway(final String device, final Class<T> clazz,
            final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = getDeviceGateway(device, clazz);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * Get all devices those are claimed by one owner
     *
     * @param type object that will define what elements will returned by this method
     * @return a List with all devices those belongs to the owner
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> List<T> getDeviceList(final KnotList<T> type)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // Get all devices those are claimed by one owner
        final String endPoint = mEndPoint + MY_DEVICES_PATH;
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            if (response.code() != HttpURLConnection.HTTP_OK) {
                return null;
            }
            JsonElement jsonElement = new JsonParser().parse(response.body().string());
            JsonArray jsonArray = jsonElement.getAsJsonObject().getAsJsonArray(JSON_DEVICES);
            return mGson.fromJson(jsonArray.toString(), type);
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #getDeviceList(KnotList<T>)}
     *
     * @param type     object that will define what elements will returned by this method
     * @param callback callback
     * @return a List with all devices those belongs to the owner
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingDevice> void getDeviceList(final KnotList<T> type,
            final Event<List<T>> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    List<T> result = getDeviceList(type);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    // Data methods

    /**
     * Create data for one device. If the device has an owner, it is necessary that the owner
     * param be the same of the device owner.
     *
     * @param device the device identifier (uuid)
     * @param data   data that will be created for device
     * @return a boolean value to indicate if the data could be create for device
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingData> boolean createData(String device, T data)
            throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        // Create data for one device. If the device has an owner, it is necessary that the owner
        // param be the same of the device owner
        final String endPoint = mEndPoint + DATA_PATH + device;
        String json = mGson.toJson(data);
        RequestBody body = createRequestBodyWith(json);
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).post(body).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            return response.code() == HttpURLConnection.HTTP_CREATED;
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #createData(String, AbstractThingData)}
     *
     * @param device   the device identifier (uuid)
     * @param data     data that will be created for device
     * @param callback Callback for this method
     * @return a boolean value to indicate if the data could be create for device
     * @throws KnotException
     */
    public <T extends AbstractThingData> void createData(final String device, final T data,
            final Event<Boolean> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    Boolean result = createData(device, data);
                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    /**
     * @param device the device identifier (uuid)
     * @param type   object that will define what elements will returned by this method
     * @param knotQueryData  Date query
     * @return a List with data of the device
     * @throws KnotException KnotException
     */
    public <T extends AbstractThingData> List<T> getDataList(String device, final KnotList<T> type,
            KnotQueryData knotQueryData) throws InvalidDeviceOwnerStateException, KnotException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        final String endPoint = mEndPoint + DATA_PATH + device + getDataParameter(knotQueryData);
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            JsonElement jsonElement = new JsonParser().parse(response.body().string());
            JsonArray jsonArray = jsonElement.getAsJsonObject().getAsJsonArray(JSON_DATA);

            if (jsonArray == null || jsonArray.size() == 0) {
                return mGson.fromJson(EMPTY_ARRAY, type);
            }

            return mGson.fromJson(jsonArray.toString(), type);
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Async version of {@link #getDataList(String, KnotList, KnotQueryData, Event)}
     *
     * @param device   the device identifier (uuid)
     * @param type     object that will define what elements will returned by this method
     * @param callback Callback for this method
     * @param knotQueryData  Date query
     * @return a List with data of the device
     */
    public <T extends AbstractThingData> void getDataList(final String device, final KnotList<T> type,
            final KnotQueryData knotQueryData, final Event<List<T>> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    List<T> result = getDataList(device, type, knotQueryData);

                    dispatchSuccess(callback, result);
                } catch (KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    //Message

    /**
     * Send a message in Meshblu instance
     *
     * @param message model sample to create a new message. Basically this message model
     *                contains attributes that will be send into Meshblu.
     * @return New message with meshblu content.
     * @throws KnotException KnotException
     * @see AbstractThingMessage
     */
    public <T extends AbstractThingMessage> T sendMessage(T message)
            throws KnotException, InvalidDeviceOwnerStateException {
        // Check if the current state of device owner is valid
        if (!isValidDeviceOwner()) {
            throw new InvalidDeviceOwnerStateException("The device owner is invalid or null");
        }

        final String endPoint = mEndPoint + MESSAGE;
        String json = mGson.toJson(message);

        RequestBody body = createRequestBodyWith(json);
        Request request = generateBasicRequestBuild(this.abstractDeviceOwner.getUuid(),
                this.abstractDeviceOwner.getToken(), endPoint).post(body).build();

        try {
            Response response = mHttpClient.newCall(request).execute();
            JsonElement jsonElement = new JsonParser().parse(response.body().string());

            return (T) mGson.fromJson(jsonElement.toString(), message.getClass());
        } catch (Exception e) {
            throw new KnotException(e);
        }
    }

    /**
     * Send a message in Meshblu instance
     *
     * @param message model sample to create a new message. Basically this message model
     *                contains attributes that will be send into Meshblu.
     * @return New message with meshblu content.
     * @see AbstractThingMessage
     */
    public <T extends AbstractThingMessage> void sendMessage(final T message, final Event<T> callback) {
        new Thread() {
            @Override
            public void run() {
                try {
                    T result = sendMessage(message);
                    dispatchSuccess(callback, result);
                } catch (final KnotException | InvalidDeviceOwnerStateException e) {
                    dispatchError(callback, e);
                }
            }
        }.start();
    }

    ///////////////////////////////////////////////////////////////////////////
    // Private methods
    ///////////////////////////////////////////////////////////////////////////
    private RequestBody createEmptyRequestBody() {
        return RequestBody.create(JSON, EMPTY_JSON);
    }

    private RequestBody createRequestBodyWith(String data) {
        return RequestBody.create(JSON, data);
    }

    private Request.Builder generateBasicRequestBuild(String uuid, String token, String endPoint) {
        return new Request.Builder().addHeader(HEADER_AUTH_UUID, uuid).addHeader(HEADER_AUTH_TOKEN, token)
                .url(endPoint);
    }

    private Request.Builder generateBasicRequestBuild(String endPoint) {
        return new Request.Builder().url(endPoint);
    }

    private <T> void dispatchSuccess(final Event<T> callback, final T result) {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onEventFinish(result);
            }
        });
    }

    private <T> void dispatchError(final Event<T> callback, final Exception error) {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onEventError(error);
            }
        });
    }

    /**
     * Check if the current Owner device is valid
     *
     * @return true if the owner device is valid
     */
    public boolean isValidDeviceOwner() {
        return this.abstractDeviceOwner != null && !TextUtils.isEmpty(this.abstractDeviceOwner.getUuid())
                && !TextUtils.isEmpty(this.abstractDeviceOwner.getToken());
    }

    /**
     * This method is used to build the parameters
     * @param knotQueryData object with query information
     * @return String that represents a list of parameter
     */
    private String getDataParameter(KnotQueryData knotQueryData) {

        String parameter = "?";
        String and = "&";
        int amountOfKnotData = -1;

        if (knotQueryData != null) {

            if (knotQueryData.getLimit() > 0) {
                amountOfKnotData = knotQueryData.getLimit();
            }

            parameter = parameter + LIMIT + EQUAL + amountOfKnotData;

            if (knotQueryData.getStartDate() != null) {
                parameter = parameter + and + DATE_START + EQUAL
                        + DateUtils.getTimeStamp(knotQueryData.getStartDate());
            }

            if (knotQueryData.getFinishDate() != null) {
                parameter = parameter + and + DATE_FINISH + EQUAL
                        + DateUtils.getTimeStamp(knotQueryData.getFinishDate());
            }

        }

        return parameter.trim();

    }
}