All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.telekom.m2m.cot.restsdk.CloudOfThingsRestClient Maven / Gradle / Ivy

package com.telekom.m2m.cot.restsdk;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.telekom.m2m.cot.restsdk.smartrest.SmartRequest;
import com.telekom.m2m.cot.restsdk.smartrest.SmartResponse;
import com.telekom.m2m.cot.restsdk.util.CotSdkException;
import com.telekom.m2m.cot.restsdk.util.GsonUtils;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;


/**
 * Created by Patrick Steinert on 30.01.16.
 */
public class CloudOfThingsRestClient {

    private final Gson gson = GsonUtils.createGson();
    private final String encodedAuthString;
    private final String host;

    protected OkHttpClient client;

    // This is an automatic clone of {@link #client}, which can have it's own, much longer, timeouts, and because we
    // don't want a real time server advice to change timeout behaviour for the whole application:
    protected OkHttpClient realTimeClient;
    // The read timeout for the realTimeClient. It should always be set by the caller, but we store it to detect changes:
    protected Integer realTimeTimeout = 60000;


    /**
     * @param okHttpClient HTTP client that is used to interact with the API.
     * @param host URL to connect to. Must contain scheme and host, e.g. https://username.int2-ram.m2m.telekom.com
     * @param user Username for authentication.
     * @param password Password for authentication.
     */
    public CloudOfThingsRestClient(OkHttpClient okHttpClient, String host, String user, String password) {
        this.host = host;
        try {
            encodedAuthString = Base64.getEncoder().encodeToString((user + ":" + password).getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            throw new CotSdkException("Error generating auth string.", e);
        }
        client = okHttpClient;
    }

    /**
     * Executes an HTTP POST request and parses the response Header.
     * Response header 'Location' will be split to get the ID of the object (mostly created).
     *
     * @param json
     *            Request body, needs to be a json object correlating to the
     *            contentType.
     * @param api
     *            the REST API string.
     * @param contentType
     *            the Content-Type of the JSON Object.
     * @return the id of the Object.
     */
    public String doRequestWithIdResponse(String json, String api, String contentType) {

        Response response = null;
        try {
            RequestBody body = RequestBody.create(MediaType.parse(contentType), json);
            Request request = new Request.Builder()
                    .addHeader("Authorization", "Basic " + encodedAuthString)
                    .addHeader("Content-Type", contentType)
                    .addHeader("Accept", contentType)
                    // .url(tenant + ".test-ram.m2m.telekom.com/" + api)
                    .url(host + "/" + api)
                    .post(body)
                    .build();
            response = client.newCall(request).execute();
            if (!response.isSuccessful()) {
                final String err = getErrorMessage(response);
                throw new CotSdkException(response.code(), err);
            }
            String location = response.header("Location");
            String result = null;
            if (location != null) {
                String[] pathParts = location.split("\\/");
                result = pathParts[pathParts.length - 1];
            }
            return result;
        } catch (CotSdkException e) {
            // We need to rethrow this in order to not loose the status code.
            throw e;
        } catch (Exception e) {
            throw new CotSdkException("Problem: " + e.getMessage(), e);
        } finally {
            closeResponseBodyIfResponseAndBodyNotNull(response);
        }
    }


    // TODO: here the contentType is also used for the Accept header, which is dirty!
    public String doPostRequest(String json, String api, String contentType) {
        return doPostRequest(json, api, contentType, contentType);
    }


    /**
     * Executes an HTTP POST request and returns the response body as String.
     *
     * @param json
     *            Request body, needs to be a json object correlating to the
     *            contentType.
     * @param api
     *            the REST API string.
     * @param contentType
     *            the Content-Type of the JSON Object.
     * @param accept
     *            the Accept header for the request
     * @return the received JSON response body.
     */
    public String doPostRequest(String json, String api, String contentType, String accept) {

        RequestBody body = RequestBody.create(MediaType.parse(contentType), json);
        Request.Builder requestBuilder = new Request.Builder()
                .addHeader("Authorization", "Basic " + encodedAuthString)
                .url(host + "/" + api)
                .post(body);

        if (contentType != null) {
            requestBuilder.addHeader("Content-Type", contentType);
        }
        if (accept != null) {
            requestBuilder.addHeader("Accept", accept);
        }

        Response response = null;
        try {
            response = client.newCall(requestBuilder.build()).execute();
            if (!response.isSuccessful()) {
                final String err = getErrorMessage(response);
                throw new CotSdkException(response.code(), err);
            }

            String bodyContent = response.body().string();
            return bodyContent;
        } catch (IOException e) {
            throw new CotSdkException("Unexpected error during POST request.", e);
        } finally {
            closeResponseBodyIfResponseAndBodyNotNull(response);
        }
    }


    /**
     * Executes a multipart form upload of a string and returns the response body as String.
     *
     * @param file Request body, i.e. the first and only form part.
     * @param name The name of the form field.
     * @param api the URL path (without leading /)
     * @param contentType a String with the Content-Type to set in header of the request.
     * @return the response body
     */
    public String doFormUpload(String file, String name, String api, String contentType) {
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(name, "", RequestBody.create(MultipartBody.FORM, file))
                .build();

        Request request = new Request.Builder()
                .addHeader("Authorization", "Basic " + encodedAuthString)
                .addHeader("Content-Type", contentType)
                .url(host + "/" + api)
                .post(body)
                .build();

        Response response = null;
        try {
            response = client.newCall(request).execute();
            if (!response.isSuccessful()) {
                final String err = getErrorMessage(response);
                throw new CotSdkException(response.code(), err);
            }
            String bodyContent = response.body().string();
            return bodyContent;
        } catch (IOException e) {
            throw new CotSdkException("Unexpected error during POST request.", e);
        } finally {
            closeResponseBodyIfResponseAndBodyNotNull(response);
        }
    }


    /**
     * Executes an HTTP POST request and returns the response body as String.
     *
     * @param files array of byte[], one for each form field.
     * @param names the names of the form field, same order as files.
     * @param api the URL path (without leading /)
     * @return the ID from the Location header (for newly created objects), or null if there's no Location header.
     */
    public String doFormUpload(byte[][] files, String[] names, String api) {
        if (files.length != names.length) {
            throw new CotSdkException("Need to have the same number of files and names to upload (actual: "+files.length+" != "+names.length);
        }

        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy