org.commonjava.propulsor.client.http.ClientHttpSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.commonjava.propulsor.client.http.ClientHttpSupport.java

Source

/**
 * Copyright (C) 2015 John Casey (jdcasey@commonjava.org)
 *
 * 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 org.commonjava.propulsor.client.http;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.commonjava.propulsor.client.http.helper.HttpResources;
import org.commonjava.util.jhttpc.HttpFactory;
import org.commonjava.util.jhttpc.JHttpCException;
import org.commonjava.util.jhttpc.auth.ClientAuthenticator;
import org.commonjava.util.jhttpc.auth.PasswordManager;
import org.commonjava.util.jhttpc.model.SiteConfig;
import org.commonjava.util.jhttpc.model.SiteConfigBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

import static org.apache.http.entity.ContentType.APPLICATION_JSON;
import static org.commonjava.propulsor.client.http.helper.HttpResources.cleanupResources;
import static org.commonjava.propulsor.client.http.helper.HttpResources.entityToString;
import static org.commonjava.propulsor.client.http.helper.UrlUtils.buildUrl;

public class ClientHttpSupport implements AutoCloseable {
    private static final int GLOBAL_MAX_CONNECTIONS = 20;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final String baseUrl;

    private final ObjectMapper objectMapper;

    private final HttpFactory httpFactory;

    private final SiteConfig siteConfig;

    public ClientHttpSupport(final String baseUrl, final PasswordManager passwordManager, final ObjectMapper mapper)
            throws ClientHttpException {
        this.baseUrl = baseUrl;
        this.objectMapper = mapper;
        this.siteConfig = new SiteConfigBuilder("server", baseUrl).build();
        this.httpFactory = new HttpFactory(passwordManager);
    }

    public ClientHttpSupport(final String baseUrl, final ClientAuthenticator authenticator,
            final ObjectMapper mapper) throws ClientHttpException {
        this.baseUrl = baseUrl;
        this.objectMapper = mapper;
        this.siteConfig = new SiteConfigBuilder("server", baseUrl).build();
        this.httpFactory = new HttpFactory(authenticator);
    }

    public ClientHttpSupport(final SiteConfig siteConfig, final ObjectMapper mapper, final HttpFactory httpFactory)
            throws ClientHttpException {
        this.siteConfig = siteConfig;
        this.baseUrl = siteConfig.getUri();
        this.objectMapper = mapper;
        this.httpFactory = httpFactory;
    }

    public void connect() throws ClientHttpException {
        // NOP, mainly provided for extension.
    }

    public Map<String, String> head(final String path) throws ClientHttpException {
        return head(path, HttpStatus.SC_OK);
    }

    public Map<String, String> head(final String path, final int... responseCodes) throws ClientHttpException {
        connect();

        HttpHead request = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;

        try {
            request = newJsonHead(buildUrl(baseUrl, path));
            client = newClient();
            response = client.execute(request);

            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                if (sl.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
                    return null;
                }

                throw new ClientHttpException(sl.getStatusCode(),
                        "Error executing HEAD: %s. Status was: %d %s (%s)", path, sl.getStatusCode(),
                        sl.getReasonPhrase(), sl.getProtocolVersion());
            }

            final Map<String, String> headers = new HashMap<>();
            for (final Header header : response.getAllHeaders()) {
                final String name = header.getName().toLowerCase();

                if (!headers.containsKey(name)) {
                    headers.put(name, header.getValue());
                }
            }

            return headers;
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(request, response, client);
        }
    }

    public <T> T get(final String path, final Class<T> type) throws ClientHttpException {
        connect();

        HttpGet request = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            request = newJsonGet(buildUrl(baseUrl, path));
            response = client.execute(request);

            final StatusLine sl = response.getStatusLine();

            if (sl.getStatusCode() != 200) {
                if (sl.getStatusCode() == 404) {
                    return null;
                }

                throw new ClientHttpException(sl.getStatusCode(), "Error retrieving %s from: %s.\n%s",
                        type.getSimpleName(), path, new ClientHttpResponseErrorDetails(response));
            }

            final String json = entityToString(response);
            logger.debug("Got JSON:\n\n{}\n\n", json);
            final T value = objectMapper.readValue(json, type);

            logger.debug("Got result object: {}", value);

            return value;
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(request, response, client);
        }
    }

    public <T> T get(final String path, final TypeReference<T> typeRef) throws ClientHttpException {
        connect();

        HttpGet request = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            request = newJsonGet(buildUrl(baseUrl, path));
            response = client.execute(request);
            final StatusLine sl = response.getStatusLine();
            if (sl.getStatusCode() != 200) {
                if (sl.getStatusCode() == 404) {
                    return null;
                }

                throw new ClientHttpException(sl.getStatusCode(), "Error retrieving %s from: %s.\n%s",
                        typeRef.getType(), path, new ClientHttpResponseErrorDetails(response));
            }

            final String json = entityToString(response);
            final T value = objectMapper.readValue(json, typeRef);

            return value;
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(request, response, client);
        }
    }

    public HttpResources getRaw(final HttpGet req) throws ClientHttpException {
        connect();

        CloseableHttpResponse response = null;
        try {
            final CloseableHttpClient client = newClient();

            response = client.execute(req);
            return new HttpResources(req, response, client);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            // DO NOT CLOSE!!!! We're handing off control of the response to the caller!
            //            closeQuietly( response );
        }
    }

    public HttpResources getRaw(final String path) throws ClientHttpException {
        return getRaw(path, Collections.singletonMap("Accept", "*"));
    }

    public HttpResources getRaw(final String path, final Map<String, String> headers) throws ClientHttpException {
        connect();

        CloseableHttpResponse response = null;
        try {
            final HttpGet req = newRawGet(buildUrl(baseUrl, path));
            final CloseableHttpClient client = newClient();

            response = client.execute(req);
            return new HttpResources(req, response, client);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            // DO NOT CLOSE!!!! We're handing off control of the response to the caller!
            //            closeQuietly( response );
        }
    }

    public void putWithStream(final String path, final InputStream stream) throws ClientHttpException {
        putWithStream(path, stream, HttpStatus.SC_CREATED);
    }

    public void putWithStream(final String path, final InputStream stream, final int... responseCodes)
            throws ClientHttpException {
        connect();

        final HttpPut put = newRawPut(buildUrl(baseUrl, path));
        final CloseableHttpClient client = newClient();
        CloseableHttpResponse response = null;
        try {
            put.setEntity(new InputStreamEntity(stream));

            response = client.execute(put);
            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                throw new ClientProtocolException(new ClientHttpException(sl.getStatusCode(),
                        "Error in response from: %s.\n%s", path, new ClientHttpResponseErrorDetails(response)));
            }

        } catch (final ClientProtocolException e) {
            final Throwable cause = e.getCause();
            if (cause != null && (cause instanceof ClientHttpException)) {
                throw (ClientHttpException) cause;
            }

            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(put, response, client);
        }
    }

    public boolean put(final String path, final Object value) throws ClientHttpException {
        return put(path, value, HttpStatus.SC_OK, HttpStatus.SC_CREATED);
    }

    public boolean put(final String path, final Object value, final int... responseCodes)
            throws ClientHttpException {
        checkRequestValue(value);

        connect();

        HttpPut put = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            put = newJsonPut(buildUrl(baseUrl, path));

            put.setEntity(new StringEntity(objectMapper.writeValueAsString(value), APPLICATION_JSON));

            response = client.execute(put);
            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                throw new ClientHttpException(sl.getStatusCode(), "Error in response from: %s.\n%s", path,
                        new ClientHttpResponseErrorDetails(response));
            }
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(put, response, client);
        }

        return true;
    }

    public HttpResources execute(HttpRequestBase request) throws ClientHttpException {
        connect();

        CloseableHttpResponse response = null;
        try {
            final CloseableHttpClient client = newClient();

            response = client.execute(request);
            return new HttpResources(request, response, client);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            // DO NOT CLOSE!!!! We're handing off control of the response to the caller!
            //            closeQuietly( response );
        }
    }

    public HttpResources postRaw(final String path, Object value) throws ClientHttpException {
        return postRaw(path, value, Collections.singletonMap("Accept", "*"));
    }

    public HttpResources postRaw(final String path, Object value, final Map<String, String> headers)
            throws ClientHttpException {
        checkRequestValue(value);
        connect();

        CloseableHttpResponse response = null;
        try {
            final HttpPost req = newRawPost(buildUrl(baseUrl, path));
            if (headers != null) {
                for (String key : headers.keySet()) {
                    req.setHeader(key, headers.get(key));
                }
            }

            req.setEntity(new StringEntity(objectMapper.writeValueAsString(value), APPLICATION_JSON));

            final CloseableHttpClient client = newClient();

            response = client.execute(req);
            return new HttpResources(req, response, client);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            // DO NOT CLOSE!!!! We're handing off control of the response to the caller!
            //            closeQuietly( response );
        }
    }

    private void checkRequestValue(Object value) throws ClientHttpException {
        if (value == null) {
            throw new ClientHttpException("Cannot use null request value!");
        }
    }

    public <T> T postWithResponse(final String path, final Object value, final Class<T> type)
            throws ClientHttpException {
        return postWithResponse(path, value, type, HttpStatus.SC_CREATED, HttpStatus.SC_OK);
    }

    public <T> T postWithResponse(final String path, final Object value, final Class<T> type,
            final int... responseCodes) throws ClientHttpException {
        checkRequestValue(value);

        connect();

        HttpPost post = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            post = newJsonPost(buildUrl(baseUrl, path));

            post.setEntity(new StringEntity(objectMapper.writeValueAsString(value), APPLICATION_JSON));

            response = client.execute(post);

            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                throw new ClientHttpException(sl.getStatusCode(), "Error retrieving %s from: %s.\n%s",
                        type.getSimpleName(), path, new ClientHttpResponseErrorDetails(response));
            }

            final String json = entityToString(response);
            return objectMapper.readValue(json, type);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(post, response, client);
        }
    }

    public boolean validResponseCode(final int statusCode, final int[] responseCodes) {
        for (final int code : responseCodes) {
            if (code == statusCode) {
                return true;
            }
        }
        return false;
    }

    public <T> T postWithResponse(final String path, final Object value, final TypeReference<T> typeRef)
            throws ClientHttpException {
        return postWithResponse(path, value, typeRef, HttpStatus.SC_CREATED);
    }

    public <T> T postWithResponse(final String path, final Object value, final TypeReference<T> typeRef,
            final int... responseCodes) throws ClientHttpException {
        checkRequestValue(value);

        connect();

        HttpPost post = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            post = newJsonPost(buildUrl(baseUrl, path));

            post.setEntity(new StringEntity(objectMapper.writeValueAsString(value), APPLICATION_JSON));

            response = client.execute(post);

            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                throw new ClientHttpException(sl.getStatusCode(), "Error retrieving %s from: %s.\n%s",
                        typeRef.getType(), path, new ClientHttpResponseErrorDetails(response));
            }

            final String json = entityToString(response);
            return objectMapper.readValue(json, typeRef);
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(post, response, client);
        }
    }

    @Override
    public void close() throws IOException {
        logger.debug("Shutting down indy client HTTP manager");
        httpFactory.close();
    }

    public void delete(final String path) throws ClientHttpException {
        delete(path, HttpStatus.SC_NO_CONTENT);
    }

    public void delete(final String path, final int... responseCodes) throws ClientHttpException {
        connect();

        HttpDelete delete = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            delete = newDelete(buildUrl(baseUrl, path));

            response = client.execute(delete);
            final StatusLine sl = response.getStatusLine();
            if (!validResponseCode(sl.getStatusCode(), responseCodes)) {
                throw new ClientHttpException(sl.getStatusCode(), "Error deleting: %s.\n%s", path,
                        new ClientHttpResponseErrorDetails(response));
            }
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(delete, response, client);
        }
    }

    public boolean exists(final String path) throws ClientHttpException {
        return exists(path, null, HttpStatus.SC_OK);
    }

    public boolean exists(final String path, Supplier<Map<String, String>> querySupplier)
            throws ClientHttpException {
        return exists(path, querySupplier, HttpStatus.SC_OK);
    }

    public boolean exists(final String path, final int... responseCodes) throws ClientHttpException {
        return exists(path, null, responseCodes);
    }

    public boolean exists(final String path, Supplier<Map<String, String>> querySupplier,
            final int... responseCodes) throws ClientHttpException {
        connect();

        HttpHead request = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = newClient();
            request = newJsonHead(buildUrl(baseUrl, querySupplier, path));

            response = client.execute(request);
            final StatusLine sl = response.getStatusLine();
            if (validResponseCode(sl.getStatusCode(), responseCodes)) {
                return true;
            } else if (sl.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
                return false;
            }

            throw new ClientHttpException(sl.getStatusCode(), "Error checking existence of: %s.\n%s", path,
                    new ClientHttpResponseErrorDetails(response));
        } catch (final IOException e) {
            throw new ClientHttpException("Client request failed: %s", e, e.getMessage());
        } finally {
            cleanupResources(request, response, client);
        }
    }

    public void cleanup(final HttpRequest request, final HttpResponse response, final CloseableHttpClient client) {
        cleanupResources(request, response, client);
    }

    public String toServerUrl(final String... path) {
        return buildUrl(baseUrl, path);
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public CloseableHttpClient newClient() throws ClientHttpException {
        try {
            return httpFactory.createClient(siteConfig);
        } catch (JHttpCException e) {
            throw new ClientHttpException("Failed to create HTTP client: %s", e, e.getMessage());
        }
    }

    public HttpGet newRawGet(final String url) {
        final HttpGet req = new HttpGet(url);
        return req;
    }

    public HttpGet newJsonGet(final String url) {
        final HttpGet req = new HttpGet(url);
        addJsonHeaders(req);
        return req;
    }

    public HttpHead newJsonHead(final String url) {
        final HttpHead req = new HttpHead(url);
        addJsonHeaders(req);
        return req;
    }

    public void addJsonHeaders(final HttpUriRequest req) {
        req.addHeader("Accept", "application/json");
        req.addHeader("Content-Type", "application/json");
    }

    public HttpDelete newDelete(final String url) {
        final HttpDelete req = new HttpDelete(url);
        return req;
    }

    public HttpPut newJsonPut(final String url) {
        final HttpPut req = new HttpPut(url);
        addJsonHeaders(req);
        return req;
    }

    public HttpPut newRawPut(final String url) {
        final HttpPut req = new HttpPut(url);
        return req;
    }

    public HttpPost newJsonPost(final String url) {
        final HttpPost req = new HttpPost(url);
        addJsonHeaders(req);
        return req;
    }

    public HttpPost newRawPost(final String url) {
        final HttpPost req = new HttpPost(url);
        req.addHeader("Content-Type", "application/json");
        return req;
    }

    public ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    public HttpFactory getHttpFactory() {
        return httpFactory;
    }

}