org.wso2.carbon.apimgt.hybrid.gateway.common.util.HttpRequestUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.apimgt.hybrid.gateway.common.util.HttpRequestUtil.java

Source

/*
 * Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.apimgt.hybrid.gateway.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.util.EntityUtils;
import org.wso2.carbon.apimgt.hybrid.gateway.common.config.ConfigManager;
import org.wso2.carbon.apimgt.hybrid.gateway.common.exception.OnPremiseGatewayException;

import java.io.IOException;
import java.net.HttpURLConnection;

/**
 * Utility methods for HTTP requests
 */
public class HttpRequestUtil {

    private static final Log log = LogFactory.getLog(HttpRequestUtil.class);
    private static final String NOT_FOUND_ERROR_MSG = "Failed with HTTP error code : "
            + HttpURLConnection.HTTP_NOT_FOUND + " (Not Found). URI is incorrect.";
    private static final String AUTH_ERROR_MSG = "Failed with HTTP error code : "
            + HttpURLConnection.HTTP_UNAUTHORIZED + " (Unauthorized). Credentials used are incorrect.";

    private static final String AUTH_FORBIDDEN_ERROR_MSG = "Failed with HTTP error code : "
            + HttpURLConnection.HTTP_UNAUTHORIZED
            + " (Unauthorized). User does not have permissions to perform the action.";

    private HttpRequestUtil() {
    }

    /**
     * Executes the HTTPMethod with retry.
     *
     * @param httpClient     HTTPClient
     * @param httpMethod     HTTPMethod
     * @param retryCount No of retries
     * @return response. it will return an empty string if response body is null
     * @throws OnPremiseGatewayException throws {@link OnPremiseGatewayException}
     */
    public static String executeHTTPMethodWithRetry(HttpClient httpClient, HttpRequestBase httpMethod,
            int retryCount) throws OnPremiseGatewayException {

        String result = OnPremiseGatewayConstants.EMPTY_STRING;
        HttpResponse response;
        int executionCount = 0;
        String methodName = httpMethod.getMethod();
        String uri = getURI(httpMethod);

        //Add an unique identifier as a custom header for distinguishing requests from different micro gateways.
        String token = ConfigManager.getConfigManager()
                .getProperty(OnPremiseGatewayConstants.API_REQUEST_UNIQUE_IDENTIFIER);
        if (StringUtils.isNotBlank(token)
                && !(OnPremiseGatewayConstants.API_REQUEST_UNIQUE_IDENTIFIER_HOLDER.equals(token))) {
            if (log.isDebugEnabled()) {
                log.debug("Adding unique identifier as an header to the http " + methodName + " request.");
            }
            httpMethod.addHeader(OnPremiseGatewayConstants.APT_REQUEST_TOKEN_HEADER, token);
        }
        do {
            try {
                executionCount++;
                response = httpClient.execute(httpMethod);
                if (log.isDebugEnabled()) {
                    log.debug("HTTP response code for the " + methodName + " request to URL: " + uri + " is "
                            + response);
                }
                result = handleResponse(response, methodName, true, executionCount, retryCount, uri);
                if (!OnPremiseGatewayConstants.EMPTY_STRING.equals(result)) {
                    return result;
                }
            } catch (IOException e) {
                handleExceptionWithRetry(executionCount, retryCount, methodName, uri, e);
            } finally {
                httpMethod.releaseConnection();
            }
        } while (executionCount < retryCount);
        return result;
    }

    /**
     * Executes HTTPMethod without retry
     *
     * @param httpClient HTTPClient
     * @param httpMethod HTTPMethod
     * @return response. it will return an empty string if response body is null
     * @throws OnPremiseGatewayException throws {@link OnPremiseGatewayException}
     */
    public static String executeHTTPMethod(HttpClient httpClient, HttpRequestBase httpMethod)
            throws OnPremiseGatewayException {

        String result;
        HttpResponse response;
        String uri = getURI(httpMethod);
        String methodName = httpMethod.getMethod();

        //Add an unique identifier as an custom header for distinguishing requests from different micro gateways.
        String token = ConfigManager.getConfigManager()
                .getProperty(OnPremiseGatewayConstants.API_REQUEST_UNIQUE_IDENTIFIER);
        if (StringUtils.isNotBlank(token)
                && !(OnPremiseGatewayConstants.API_REQUEST_UNIQUE_IDENTIFIER_HOLDER.equals(token))) {
            if (log.isDebugEnabled()) {
                log.debug("Adding unique identifier as an header to the http " + methodName + " request.");
            }
            httpMethod.addHeader(OnPremiseGatewayConstants.APT_REQUEST_TOKEN_HEADER, token);
        }
        try {
            response = httpClient.execute(httpMethod);
            if (log.isDebugEnabled()) {
                log.debug("HTTP response code for the " + methodName + " request: " + uri + " is " + response);
            }
            result = handleResponse(response, methodName, false, 0, 0, uri);
        } catch (IOException e) {
            throw new OnPremiseGatewayException(methodName + " request failed for URI: " + uri, e);
        } finally {
            httpMethod.releaseConnection();
        }
        return result;
    }

    private static String handleResponse(HttpResponse response, String methodName, boolean retry,
            int executionCount, int retryCount, String uri) throws OnPremiseGatewayException {
        switch (response.getStatusLine().getStatusCode()) {
        case HttpStatus.SC_OK:
            return handleSuccessCase(response);

        case HttpStatus.SC_CREATED:
            return handleSuccessCase(response);

        case HttpStatus.SC_ACCEPTED:
            return handleSuccessCase(response);

        case HttpStatus.SC_NOT_FOUND:
            throw new OnPremiseGatewayException(NOT_FOUND_ERROR_MSG);

        case HttpStatus.SC_UNAUTHORIZED:
            throw new OnPremiseGatewayException(AUTH_ERROR_MSG);

        case HttpStatus.SC_FORBIDDEN:
            throw new OnPremiseGatewayException(AUTH_FORBIDDEN_ERROR_MSG);

        default:
            if (retry) {
                handleDefaultCaseWithRetry(executionCount, response, retryCount, methodName, uri);
            } else {
                throw new OnPremiseGatewayException(
                        methodName + " request failed for URI: " + uri + " with HTTP error code : " + response);
            }
        }
        return OnPremiseGatewayConstants.EMPTY_STRING;
    }

    /**
     * Handles the default HTTP 2XX response
     *
     * @param response http response
     * @return validates the response
     * @throws OnPremiseGatewayException throws {@link OnPremiseGatewayException}
     */
    private static String handleSuccessCase(HttpResponse response) throws OnPremiseGatewayException {
        HttpEntity entity = response.getEntity();
        try {
            return entity != null ? EntityUtils.toString(entity, OnPremiseGatewayConstants.DEFAULT_CHARSET) : null;
        } catch (IOException e) {
            throw new OnPremiseGatewayException("Error occurred constructing the response string");
        }
    }

    /**
     * Handles the exceptions with retries
     *
     * @param executionCount number of retries configured
     * @param retryCount     current retry
     * @param methodName     HTTP method name
     * @param uri            URI used
     * @param ex             exception thrown
     * @throws OnPremiseGatewayException throws {@link OnPremiseGatewayException}
     */
    private static void handleExceptionWithRetry(int executionCount, int retryCount, String methodName, String uri,
            Exception ex) throws OnPremiseGatewayException {
        if (executionCount >= retryCount) {
            throw new OnPremiseGatewayException(methodName + " request failed for the maximum no. of attempts("
                    + retryCount + ") for URL: " + uri, ex);
        } else {
            log.warn(methodName + " request failed for URL: " + uri + " with exception : " + ex.getMessage()
                    + ". Retry attempt: " + executionCount + "/" + retryCount);
        }
    }

    /**
     * Handles the default case of the switch cases
     *
     * @param executionCount number of retries configured
     * @param response       http response
     * @param retryCount     current retry
     * @param methodName     HTTP method name
     * @param uri            URI used
     * @throws OnPremiseGatewayException throws {@link OnPremiseGatewayException}
     */
    private static void handleDefaultCaseWithRetry(int executionCount, HttpResponse response, int retryCount,
            String methodName, String uri) throws OnPremiseGatewayException {
        if (executionCount >= retryCount) {
            throw new OnPremiseGatewayException(
                    methodName + " request failed for the " + retryCount + " attempt for URI: " + uri
                            + " with HTTP error code: " + response.getStatusLine().getStatusCode());
        } else {
            log.warn(methodName + " request failed for URI: " + uri + " with HTTP error code: "
                    + response.getStatusLine().getStatusCode() + ". Retry: " + executionCount + "/" + retryCount);
        }
    }

    /**
     * Get URI from the http method
     *
     * @param httpMethod http method
     * @return URI string
     */
    private static String getURI(HttpRequestBase httpMethod) {
        return httpMethod.getURI().toString();
    }
}