com.arrow.acs.client.api.ApiAbstract.java Source code

Java tutorial

Introduction

Here is the source code for com.arrow.acs.client.api.ApiAbstract.java

Source

/*******************************************************************************
 * Copyright (c) 2017 Arrow Electronics, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License 2.0
 * which accompanies this distribution, and is available at
 * http://apache.org/licenses/LICENSE-2.0
 *
 * Contributors:
 *     Arrow Electronics, Inc.
 *******************************************************************************/
package com.arrow.acs.client.api;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;

import com.arrow.acs.AcsErrorResponse;
import com.arrow.acs.ApiHeaders;
import com.arrow.acs.ApiRequestSigner;
import com.arrow.acs.JsonUtils;
import com.arrow.acs.Loggable;
import com.arrow.acs.client.AcsClientException;
import com.arrow.acs.client.model.ExternalHidModel;
import com.arrow.acs.client.model.HidModel;
import com.arrow.acs.client.model.ListResultModel;
import com.arrow.acs.client.model.ModelAbstract;
import com.arrow.acs.client.model.PagingResultModel;
import com.arrow.acs.client.model.StatusModel;
import com.arrow.acs.client.search.SearchCriteria;
import com.arrow.acs.client.search.SearchCriteria.Pair;
import com.fasterxml.jackson.core.type.TypeReference;

public abstract class ApiAbstract extends Loggable {

    private static final String SIGNATURE_MSG = "signature: %s";
    private static final String MIME_APPLICATION_JSON = "application/json";

    private ApiConfig apiConfig;

    public void setApiConfig(ApiConfig apiConfig) {
        this.apiConfig = apiConfig;
    }

    public ApiConfig getApiConfig() {
        return apiConfig;
    }

    public URI buildUri(String path) {
        Validate.notNull(apiConfig, "apiConfig is not set");
        try {
            URIBuilder uriBuilder;
            if (!StringUtils.isBlank(apiConfig.getBaseUrl())) {
                uriBuilder = new URIBuilder(apiConfig.getBaseUrl());
            } else {
                uriBuilder = new URIBuilder();
            }
            if (!StringUtils.isEmpty(path)) {
                StringBuilder pathBuilder = new StringBuilder()
                        .append(uriBuilder.getPath() != null ? uriBuilder.getPath() : "").append("/").append(path);
                uriBuilder.setPath(pathBuilder.toString().replaceAll("/{2,}", "/"));
            }
            return uriBuilder.build();
        } catch (URISyntaxException e) {
            throw new AcsClientException("Invalid base: " + apiConfig.getBaseUrl() + ", path: " + path,
                    new AcsErrorResponse());
        }
    }

    public <T> T execute(HttpEntityEnclosingRequestBase request, String payload, Class<T> clazz)
            throws IOException {
        Validate.notNull(apiConfig, "apiConfig is not set");
        return JsonUtils.fromJson(execute(sign(request, payload)), clazz);
    }

    public <T> T execute(HttpEntityEnclosingRequestBase request, String payload, TypeReference<T> typeRef)
            throws IOException {
        Validate.notNull(apiConfig, "apiConfig is not set");
        return JsonUtils.fromJson(execute(sign(request, payload)), typeRef);
    }

    public <T> T execute(HttpRequestBase request, Class<T> clazz) throws IOException {
        Validate.notNull(apiConfig, "apiConfig is not set");
        return JsonUtils.fromJson(execute(sign(request)), clazz);
    }

    public <T> T execute(HttpRequestBase request, TypeReference<T> typeRef) throws IOException {
        Validate.notNull(apiConfig, "apiConfig is not set");
        return JsonUtils.fromJson(execute(sign(request)), typeRef);
    }

    public <T> T execute(HttpRequestBase request, SearchCriteria criteria, TypeReference<T> typeRef)
            throws IOException {
        Validate.notNull(criteria, "criteria is null");
        Validate.notNull(apiConfig, "apiConfig is not set");
        String method = "execute";
        Instant timestamp = Instant.now();
        ApiRequestSigner signer = getSigner(request, timestamp);
        for (Pair entry : criteria.getAllCriteria()) {
            signer.parameter(entry.getName(), entry.getValue());
        }
        String signature = signer.signV1();
        logDebug(method, SIGNATURE_MSG, signature);
        addHeaders(request, timestamp, signature);
        return JsonUtils.fromJson(execute(request), typeRef);
    }

    private String execute(HttpRequestBase request) throws IOException {
        Validate.notNull(request, "request is null");
        String method = "execute";
        logInfo(method, "url: %s", request.getURI());
        try (CloseableHttpClient httpClient = ConnectionManager.getInstance().getConnection()) {
            HttpResponse response = httpClient.execute(request);
            String content = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                logError(method, "ERROR: %s", content);
                String message = String.format("error response: %d - %s, error: %s", statusCode,
                        response.getStatusLine().getReasonPhrase(), content);
                throw new AcsClientException(message, JsonUtils.fromJson(content, AcsErrorResponse.class));
            }
            return content;
        }
    }

    private ApiRequestSigner getSigner(HttpRequestBase request, Instant timestamp) {
        Validate.notNull(request, "request is null");
        Validate.notNull(timestamp, "timestamp is null");
        Validate.notEmpty(apiConfig.getApiKey(), "apiKey is empty");
        Validate.notEmpty(apiConfig.getSecretKey(), "secretKey is empty");
        return ApiRequestSigner.create(apiConfig.getSecretKey()).method(request.getMethod())
                .canonicalUri(request.getURI().getPath()).apiKey(apiConfig.getApiKey())
                .timestamp(timestamp.toString());
    }

    private HttpRequestBase sign(HttpRequestBase request) {
        String method = "sign";
        Instant timestamp = Instant.now();
        String signature = getSigner(request, timestamp).signV1();
        logDebug(method, SIGNATURE_MSG, signature);
        addHeaders(request, timestamp, signature);
        return request;
    }

    private HttpEntityEnclosingRequestBase sign(HttpEntityEnclosingRequestBase request, String payload) {
        String method = "sign";
        Instant timestamp = Instant.now();
        String signature = getSigner(request, timestamp).payload(payload).signV1();
        logDebug(method, SIGNATURE_MSG, signature);
        addHeaders(request, timestamp, signature);
        request.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
        return request;
    }

    private void addHeaders(HttpRequestBase msg, Instant timestamp, String signature) {
        Validate.notNull(msg, "msg is null");
        Validate.notNull(timestamp, "timestamp is null");
        Validate.notEmpty(apiConfig.getApiKey(), "apiKey is empty");
        msg.addHeader(HttpHeaders.CONTENT_TYPE, MIME_APPLICATION_JSON);
        msg.addHeader(HttpHeaders.ACCEPT, MIME_APPLICATION_JSON);
        msg.addHeader(ApiHeaders.X_ARROW_APIKEY, apiConfig.getApiKey());
        msg.addHeader(ApiHeaders.X_ARROW_DATE, timestamp.toString());
        msg.addHeader(ApiHeaders.X_ARROW_VERSION, ApiHeaders.X_ARROW_VERSION_1);
        msg.addHeader(ApiHeaders.X_ARROW_SIGNATURE, signature);
    }

    protected void log(String method, ModelAbstract<?> model) {
        logDebug(method, "hid: %s", model.getHid());
    }

    protected void log(String method, HidModel model) {
        logDebug(method, "hid: %s, message: %s", model.getHid(), model.getMessage());
    }

    protected void log(String method, ExternalHidModel model) {
        logDebug(method, "hid: %s, externalId: %s, message: %s", model.getHid(), model.getExternalId(),
                model.getMessage());
    }

    protected void log(String method, StatusModel model) {
        logDebug(method, "status: %s, message: %s", model.getStatus(), model.getMessage());
    }

    protected void log(String method, ListResultModel<?> model) {
        logDebug(method, "size: %d", model.getSize());
    }

    protected void log(String method, PagingResultModel<?> model) {
        logDebug(method, "size: %d, totalSize: %d, page: %d, totalPage: %d", model.getSize(), model.getTotalSize(),
                model.getPage(), model.getTotalPages());
    }

    protected AcsClientException handleException(Throwable t) {
        String method = "handleException";
        if (t instanceof AcsClientException) {
            return (AcsClientException) t;
        } else {
            logError(method, t);
            return new AcsClientException(t);
        }
    }
}