com.opower.rest.client.generator.executors.ApacheHttpClient4Executor.java Source code

Java tutorial

Introduction

Here is the source code for com.opower.rest.client.generator.executors.ApacheHttpClient4Executor.java

Source

/**
 *    Copyright 2014 Opower, Inc.
 *    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 com.opower.rest.client.generator.executors;

import com.google.common.collect.ImmutableList;
import com.opower.rest.client.generator.core.BaseClientResponse;
import com.opower.rest.client.generator.core.ClientRequest;
import com.opower.rest.client.generator.core.ClientRequestFilter;
import com.opower.rest.client.generator.core.ClientResponse;
import com.opower.rest.client.generator.core.SelfExpandingBufferredInputStream;
import com.opower.rest.client.generator.util.CaseInsensitiveMap;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * ClientExecutor implementation that uses HttpClient 4.
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 *
 */
public class ApacheHttpClient4Executor extends AbstractClientExecutor {
    protected final HttpClient httpClient;
    protected boolean createdHttpClient;
    protected HttpContext httpContext;
    protected boolean closed;

    /**
     * Create an instance using the DefaultHttpClient.
     */
    public ApacheHttpClient4Executor() {
        this(new DefaultHttpClient(new PoolingClientConnectionManager()), ImmutableList.<ClientRequestFilter>of());
    }

    public ApacheHttpClient4Executor(List<ClientRequestFilter> requestFilters) {
        this(new DefaultHttpClient(new PoolingClientConnectionManager()), requestFilters);
    }

    /**
     * Create an instance using the specified HttpClient.
     * @param httpClient the HttpClient to use
     */
    public ApacheHttpClient4Executor(HttpClient httpClient) {
        this(httpClient, ImmutableList.<ClientRequestFilter>of());
    }

    public ApacheHttpClient4Executor(HttpClient httpClient, List<ClientRequestFilter> requestFilters) {
        super(requestFilters);
        this.httpClient = checkNotNull(httpClient);
    }

    /**
     * Extracts the headers from the given HttpResponse.
     * @param response the HttpResponse to get the headers from
     * @return A map of the headers found on the HttpResponse
     */
    public static CaseInsensitiveMap<String> extractHeaders(HttpResponse response) {
        final CaseInsensitiveMap<String> headers = new CaseInsensitiveMap<String>();

        for (Header header : response.getAllHeaders()) {
            headers.add(header.getName(), header.getValue());
        }
        return headers;
    }

    @Override
    @SuppressWarnings("unchecked")
    public ClientResponse execute(ClientRequest request) throws Exception {
        String uri = request.getUri();
        final HttpRequestBase httpMethod = createHttpMethod(uri, request.getHttpMethod());
        loadHttpMethod(request, httpMethod);

        final HttpResponse res = this.httpClient.execute(httpMethod, this.httpContext);

        BaseClientResponse response = new BaseClientResponse(new SimpleBaseClientResponseStreamFactory(res), this,
                request.getErrorStatusCriteria());

        response.setStatus(res.getStatusLine().getStatusCode());
        response.setHeaders(extractHeaders(res));
        response.setProviders(request.getProviders());
        return response;
    }

    private HttpRequestBase createHttpMethod(String url, String restVerb) {
        if ("GET".equals(restVerb)) {
            return new HttpGet(url);
        } else if ("POST".equals(restVerb)) {
            return new HttpPost(url);
        } else {
            final String verb = restVerb;
            return new HttpPost(url) {
                @Override
                public String getMethod() {
                    return verb;
                }
            };
        }
    }

    public void loadHttpMethod(final ClientRequest request, HttpRequestBase httpMethod) throws Exception {
        if (httpMethod instanceof HttpGet && request.followRedirects()) {
            HttpClientParams.setRedirecting(httpMethod.getParams(), true);
        } else {
            HttpClientParams.setRedirecting(httpMethod.getParams(), false);
        }

        if (request.getBody() != null && !request.getFormParameters().isEmpty())
            throw new RuntimeException("You cannot send both form parameters and an entity body");

        if (!request.getFormParameters().isEmpty()) {
            commitHeaders(request, httpMethod);
            HttpPost post = (HttpPost) httpMethod;

            List<NameValuePair> formparams = new ArrayList<NameValuePair>();

            for (Map.Entry<String, List<String>> formParam : request.getFormParameters().entrySet()) {
                List<String> values = formParam.getValue();
                for (String value : values) {
                    formparams.add(new BasicNameValuePair(formParam.getKey(), value));
                }
            }

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
            post.setEntity(entity);
        } else if (request.getBody() != null) {
            if (httpMethod instanceof HttpGet)
                throw new RuntimeException("A GET request cannot have a body.");

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                request.writeRequestBody(request.getHeadersAsObjects(), baos);
                ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray()) {
                    @Override
                    public Header getContentType() {
                        return new BasicHeader("Content-Type", request.getBodyContentType().toString());
                    }
                };
                HttpPost post = (HttpPost) httpMethod;
                commitHeaders(request, httpMethod);
                post.setEntity(entity);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else // no body
        {
            commitHeaders(request, httpMethod);
        }
    }

    public void commitHeaders(ClientRequest request, HttpRequestBase httpMethod) {
        MultivaluedMap<String, String> headers = request.getHeaders();
        for (Map.Entry<String, List<String>> header : headers.entrySet()) {
            List<String> values = header.getValue();
            for (String value : values) {
                //               System.out.println(String.format("setting %s = %s", header.getKey(), value));
                httpMethod.addHeader(header.getKey(), value);
            }
        }
    }

    @Override
    public void close() {
        if (closed)
            return;

        if (createdHttpClient && httpClient != null) {
            ClientConnectionManager manager = httpClient.getConnectionManager();
            if (manager != null) {
                manager.shutdown();
            }
        }
        closed = true;
    }

    //CHECKSTYLE:OFF
    @Override
    public void finalize() throws Throwable {
        close();
        super.finalize();
    }//CHECKSTYLE:ON

    private class SimpleBaseClientResponseStreamFactory
            implements BaseClientResponse.BaseClientResponseStreamFactory {
        private final HttpResponse res;
        private InputStream stream;

        private SimpleBaseClientResponseStreamFactory(HttpResponse res) {
            this.res = res;
        }

        public InputStream getInputStream() throws IOException {
            if (this.stream == null) {
                HttpEntity entity = this.res.getEntity();
                if (entity == null) {
                    return null;
                }
                this.stream = new SelfExpandingBufferredInputStream(entity.getContent());
            }
            return this.stream;
        }

        public void performReleaseConnection() {
            // Apache Client 4 is stupid,  You have to get the InputStream and close it if there is an entity
            // otherwise the connection is never released.  There is, of course, no close() method on response
            // to make this easier.
            try {
                if (this.stream != null) {
                    this.stream.close();
                } else {
                    InputStream is = getInputStream();
                    if (is != null) {
                        is.close();
                    }
                }
            } catch (Exception ignore) {
            }
        }
    }

}