io.kahu.hawaii.util.call.http.HttpRequestBuilder.java Source code

Java tutorial

Introduction

Here is the source code for io.kahu.hawaii.util.call.http.HttpRequestBuilder.java

Source

/**
 * Copyright 2015 Q24
 *
 * Licensed 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 io.kahu.hawaii.util.call.http;

import io.kahu.hawaii.util.call.*;
import io.kahu.hawaii.util.call.dispatch.RequestDispatcher;
import io.kahu.hawaii.util.call.http.util.UriBuilder;
import io.kahu.hawaii.util.call.log.CallLogger;
import io.kahu.hawaii.util.exception.ServerError;
import io.kahu.hawaii.util.exception.ServerException;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.plexus.util.StringUtils;

@NotThreadSafe
public class HttpRequestBuilder<T> implements RequestBuilder<T> {
    private static final HttpClientBuilder HTTP_CLIENT_BUILDER = HttpClientBuilder.create()
            .disableContentCompression();

    private static final String JSON = "application/json";
    private static final String TEXT = "text/plain";
    private static final String UTF_8 = "UTF-8";

    @SuppressWarnings("rawtypes")
    private Constructor<HttpRequestBuilder> constructor;

    private boolean active = false;

    private final Map<String, String> headers = new HashMap<>();
    private String mimeType = TEXT;
    private String characterEncoding = UTF_8;

    private String[] pathVariables;

    private Map<String, Object> queryParameters;

    private ResponseCallback<T> callback;

    private HttpHeaderProvider httpHeaderProvider;

    private HttpRequestCredentials credentials;

    // Post
    private String payload;
    private Map<String, Object> payloads;

    @Deprecated
    public HttpRequestBuilder(RequestDispatcher requestDispatcher, HttpRequestContext<T> requestContext,
            ResponseHandler<HttpResponse, T> responseHandler, CallLogger<T> logger,
            HttpHeaderProvider httpHeaderProvider) throws ServerException {
        this(requestDispatcher, requestContext, responseHandler, logger);
        this.httpHeaderProvider = httpHeaderProvider;
    }

    @Deprecated
    public HttpRequestBuilder(RequestDispatcher requestDispatcher, HttpRequestContext<T> requestContext,
            ResponseHandler<HttpResponse, T> responseHandler, CallLogger<T> logger) throws ServerException {
        this(new RequestPrototype<>(requestDispatcher, requestContext, responseHandler, logger));
    }

    public HttpRequestBuilder(RequestPrototype<HttpResponse, T> prototype, HttpHeaderProvider httpHeaderProvider,
            HttpRequestCredentials credentials) throws ServerException {
        this(prototype, httpHeaderProvider);
        this.credentials = credentials;

    }

    public HttpRequestBuilder(RequestPrototype<HttpResponse, T> prototype, HttpHeaderProvider httpHeaderProvider)
            throws ServerException {
        this(prototype);
        this.httpHeaderProvider = httpHeaderProvider;
    }

    public HttpRequestBuilder(RequestPrototype<HttpResponse, T> prototype) throws ServerException {
        this.prototype = new RequestPrototype(prototype);
        setConstructor();
    }

    private RequestPrototype<HttpResponse, T> prototype;

    private void setConstructor() throws ServerException {
        try {
            constructor = HttpRequestBuilder.class.getConstructor(RequestPrototype.class, HttpHeaderProvider.class,
                    HttpRequestCredentials.class);
        } catch (NoSuchMethodException | SecurityException e) {
            throw new ServerException(ServerError.UNEXPECTED_EXCEPTION, e);
        }
    }

    @SuppressWarnings("unchecked")
    public HttpRequestBuilder<T> newInstance() throws ServerException {
        try {
            return constructor.newInstance(prototype, httpHeaderProvider, credentials).activate();
        } catch (Exception e) {
            throw new ServerException(ServerError.UNEXPECTED_EXCEPTION, e);
        }
    }

    private HttpRequestBuilder<T> activate() {
        this.active = true;
        return this;
    }

    public HttpRequestBuilder<T> withMimeType(String mimeType) {
        assert active : "Not active.";
        this.mimeType = mimeType;
        return this;
    }

    public HttpRequestBuilder<T> withCharacterEncoding(String characterEncoding) {
        assert active : "Not active.";
        this.characterEncoding = characterEncoding;
        return this;
    }

    public HttpRequestBuilder<T> withHeader(String name, String value) {
        assert active : "Not active.";
        this.headers.put(name, value);
        return this;
    }

    public HttpRequestBuilder<T> withHeaders(Map<String, String> headers) {
        assert active : "Not active.";
        this.headers.putAll(headers);
        return this;
    }

    public HttpRequestBuilder<T> withPathVariables(String... pathVariables) {
        assert active : "Not active.";
        this.pathVariables = pathVariables;
        return this;
    }

    public HttpRequestBuilder<T> withQueryParameters(Map<String, Object> queryParameters) {
        assert active : "Not active.";
        this.queryParameters = queryParameters;
        return this;
    }

    public HttpRequestBuilder<T> withPayload(String payload) {
        assert active : "Not active.";
        this.payload = payload;
        return this;
    }

    public HttpRequestBuilder<T> withPayload(JSONObject payload) {
        assert active : "Not active";
        withMimeType(JSON);
        withPayload(payload.toString());
        return this;
    }

    public HttpRequestBuilder<T> withPayload(JSONArray payload) {
        assert active : "Not active";
        withMimeType(JSON);
        withPayload(payload.toString());
        return this;
    }

    public HttpRequestBuilder<T> withPayload(Map<String, Object> payloads) {
        assert active : "Not active";
        this.payloads = payloads;
        withMimeType("application/x-www-form-urlencoded");
        return this;
    }

    public HttpRequestBuilder<T> withCallback(ResponseCallback<T> callback) {
        this.callback = callback;
        return this;
    }

    public HttpRequestBuilder<T> withResponseHandler(ResponseHandler<HttpResponse, T> responseHandler) {
        prototype.setResponseHandler(responseHandler);
        return this;
    }

    public HttpRequestBuilder<T> withCredentials(HttpRequestCredentials credentials) {
        this.credentials = credentials;
        return this;
    }

    public Request<T> build() throws ServerException {
        assert active : "Not active.";
        AbortableHttpRequest<T> request = null;
        URI uri = getUri();

        HttpMethod method = getRequestContext().getMethod();
        switch (method) {
        case GET:
            // if payload != null throw exception?
            request = new GetRequest<>(prototype, uri);
            break;
        case POST:
            request = new PostRequest<>(prototype, uri);

            HttpEntity httpEntity = null;
            if (payload != null) {
                httpEntity = new StringEntity(payload, ContentType.create(mimeType, characterEncoding));
            }
            if (payloads != null) {
                List<NameValuePair> params = new ArrayList<>();
                for (Entry<String, Object> entry : payloads.entrySet()) {
                    entry.getValue();
                    String stringValue = StringUtils.defaultString(entry.getValue());
                    params.add(new BasicNameValuePair(entry.getKey(), stringValue));
                }
                try {
                    httpEntity = new UrlEncodedFormEntity(params);
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (httpEntity != null) {
                ((HttpPost) request.getHttpRequest()).setEntity(httpEntity);
            }
            break;
        default:
            throw new ServerException(ServerError.METHOD_ERROR, "Method '" + method + "' is not supported.");
        }

        addHeaders();

        Set<Entry<String, String>> entrySet = headers.entrySet();
        for (Entry<String, String> entry : entrySet) {
            request.getHttpRequest().addHeader(entry.getKey(), entry.getValue());
        }

        addAuthentication(request, uri);

        request.setCallback(callback);

        request.setHttpClientBuilder(HTTP_CLIENT_BUILDER);
        return request;
    }

    private void addAuthentication(AbortableHttpRequest<T> request, URI uri) {
        if (credentials != null) {
            CredentialsProvider credentialsProvider = null;

            switch (credentials.getAuthenticationType()) {
            case BASIC:
                // fall-through to default
            default:
                BasicScheme authenticationScheme = new BasicScheme();

                credentialsProvider = new BasicCredentialsProvider();
                // Explicitly set the AuthScope to ANY_REALM in order to get
                // 'preemptive authentication' to work
                credentialsProvider.setCredentials(
                        new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_REALM,
                                authenticationScheme.getSchemeName()),
                        new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword()));

                // Create an auth cache for preemptive authentication.
                AuthCache authCache = new BasicAuthCache();
                authCache.put(new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()), authenticationScheme);
                request.getHttpClientContext().setAuthCache(authCache);

                break;
            }

            request.getHttpClientContext().setCredentialsProvider(credentialsProvider);
        }
    }

    private URI getUri() throws ServerException {
        return new UriBuilder().withBaseUrl(getRequestContext().getBaseUrl())
                .withPath(getRequestContext().getPath()).withPathVariables(pathVariables)
                .withQueryParameters(queryParameters).build();
    }

    @Override
    public HttpRequestContext<T> getRequestContext() {
        return (HttpRequestContext<T>) prototype.getContext();
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("URI: ");
        try {
            builder.append(getUri().toString()).append("\n");
        } catch (ServerException e) {
            builder.append(e).append("\n");
            // ignored
        }
        builder.append("Body: ");
        if (payload != null) {
            builder.append(payload.toString());
        }

        if (payloads != null) {
            for (Entry<String, Object> entry : payloads.entrySet()) {
                String stringValue = StringUtils.defaultString(entry.getValue());
                builder.append(entry.getKey()).append("=").append(stringValue);
                builder.append('&');
            }
        }
        return builder.toString();
    }

    private void addHeaders() throws ServerException {
        if (httpHeaderProvider != null) {
            Map<String, String> headers = httpHeaderProvider.getHeaders();
            if (headers != null) {
                withHeaders(headers);
            }
        }
    }

}