Package com.facebook.presto.jdbc.internal.airlift.http.client

Source Code of com.facebook.presto.jdbc.internal.airlift.http.client.ApacheHttpClient$ExceptionFromResponseHandler

/*
* Copyright 2010 Proofpoint, 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.facebook.presto.jdbc.internal.airlift.http.client;

import com.facebook.presto.jdbc.internal.guava.annotations.Beta;
import com.facebook.presto.jdbc.internal.guava.annotations.VisibleForTesting;
import com.facebook.presto.jdbc.internal.guava.base.Preconditions;
import com.facebook.presto.jdbc.internal.guava.collect.ArrayListMultimap;
import com.facebook.presto.jdbc.internal.guava.collect.ImmutableList;
import com.facebook.presto.jdbc.internal.guava.collect.ListMultimap;
import com.facebook.presto.jdbc.internal.guava.io.CountingInputStream;
import com.facebook.presto.jdbc.internal.guava.primitives.Ints;
import com.facebook.presto.jdbc.internal.airlift.units.Duration;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.weakref.jmx.Flatten;
import org.weakref.jmx.Managed;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Beta
public class ApacheHttpClient
        implements com.facebook.presto.jdbc.internal.airlift.http.client.HttpClient
{
    private final RequestStats stats = new RequestStats();
    private final HttpClient httpClient;
    private final List<HttpRequestFilter> requestFilters;

    public ApacheHttpClient()
    {
        this(new HttpClientConfig());
    }

    public ApacheHttpClient(HttpClientConfig config)
    {
        this(config, Collections.<HttpRequestFilter>emptySet());
    }

    public ApacheHttpClient(HttpClientConfig config, Set<? extends HttpRequestFilter> requestFilters)
    {
        Preconditions.checkNotNull(config, "config is null");
        Preconditions.checkNotNull(requestFilters, "requestFilters is null");

        PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
        connectionManager.setMaxTotal(config.getMaxConnections());
        connectionManager.setDefaultMaxPerRoute(config.getMaxConnectionsPerServer());

        BasicHttpParams httpParams = new BasicHttpParams();
        httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, Ints.checkedCast(config.getReadTimeout().toMillis()));
        httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, Ints.checkedCast(config.getConnectTimeout().toMillis()));
        httpParams.setParameter(CoreConnectionPNames.SO_LINGER, 0); // do we need this?

        DefaultHttpClient defaultHttpClient = new DefaultHttpClient(connectionManager, httpParams);
        defaultHttpClient.setKeepAliveStrategy(new FixedIntervalKeepAliveStrategy(config.getKeepAliveInterval()));
        defaultHttpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
        this.httpClient = defaultHttpClient;

        this.requestFilters = ImmutableList.copyOf(requestFilters);
    }

    @VisibleForTesting
    List<HttpRequestFilter> getRequestFilters()
    {
        return requestFilters;
    }

    @PreDestroy
    @Override
    public void close()
    {
        httpClient.getConnectionManager().shutdown();
    }

    @Managed
    @Flatten
    public RequestStats getStats()
    {
        return stats;
    }

    public <T, E extends Exception> T execute(Request request, final ResponseHandler<T, E> responseHandler)
            throws E
    {
        Preconditions.checkNotNull(request, "request is null");
        Preconditions.checkNotNull(responseHandler, "responseHandler is null");

        for (HttpRequestFilter requestFilter : requestFilters) {
            request = requestFilter.filterRequest(request);
        }

        final long requestStart = System.nanoTime();
        final StatsHttpUriRequest httpUriRequest = StatsHttpUriRequest.createGenericHttpRequest(request);
        final Request finalRequest = request;
        try {
            T value = httpClient.execute(
                    httpUriRequest,
                    new org.apache.http.client.ResponseHandler<T>()
                    {
                        @Override
                        public T handleResponse(HttpResponse httpResponse)
                                throws IOException
                        {
                            long responseStart = System.nanoTime();

                            Response response = new MyResponse(httpResponse);
                            try {
                                T value = responseHandler.handle(finalRequest, response);
                                return value;
                            }
                            catch (Exception e) {
                                throw new ExceptionFromResponseHandler(e);
                            }
                            finally {
                                Duration responseProcessingTime = Duration.nanosSince(responseStart);
                                Duration requestProcessingTime = new Duration(responseStart - requestStart, TimeUnit.NANOSECONDS);

                                stats.record(finalRequest.getMethod(),
                                        response.getStatusCode(),
                                        httpUriRequest.getBytesWritten(),
                                        response.getBytesRead(),
                                        requestProcessingTime,
                                        responseProcessingTime);
                            }
                        }
                    });
            return value;
        }
        catch (Exception e) {
            if (e instanceof ExceptionFromResponseHandler) {
                try {
                    throw (E) e.getCause();
                }
                catch (ClassCastException classCastException) {
                    // this should never happen but generics suck so be safe
                    // handler will be notified of the same exception again below
                }
            }
            else if (e instanceof ConnectTimeoutException) {
                // apache http client eats the socket timeout exception
                SocketTimeoutException socketTimeoutException = new SocketTimeoutException(e.getMessage());
                socketTimeoutException.setStackTrace(e.getStackTrace());
                return responseHandler.handleException(request, socketTimeoutException);
            }
            return responseHandler.handleException(request, e);
        }
    }

    private static class ExceptionFromResponseHandler
            extends IOException
    {
        private ExceptionFromResponseHandler(Exception cause)
        {
            super(Preconditions.checkNotNull(cause, "cause is null"));
        }
    }

    static class MyResponse
            implements Response
    {
        private final HttpResponse response;
        private CountingInputStream countingInputStream;

        public MyResponse(HttpResponse response)
        {
            this.response = response;
        }

        @Override
        public int getStatusCode()
        {
            return response.getStatusLine().getStatusCode();
        }

        @Override
        public String getStatusMessage()
        {
            return response.getStatusLine().getReasonPhrase();
        }

        @Override
        public String getHeader(String name)
        {
            Header header = response.getFirstHeader(name);
            if (header != null) {
                return header.getValue();
            }

            return null;
        }

        @Override
        public ListMultimap<String, String> getHeaders()
        {
            ArrayListMultimap<String, String> multimap = ArrayListMultimap.create();
            for (Header header : response.getAllHeaders()) {
                multimap.put(header.getName(), header.getValue());
            }
            return multimap;
        }

        @Override
        public long getBytesRead()
        {
            if (countingInputStream == null) {
                return 0;
            }
            return countingInputStream.getCount();
        }

        @Override
        public InputStream getInputStream()
                throws IOException
        {
            if (countingInputStream == null) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    InputStream content = entity.getContent();
                    if (content != null) {
                        countingInputStream = new CountingInputStream(content);
                    }
                }
            }

            if (countingInputStream == null) {
                throw new IOException("No input stream");
            }
            return countingInputStream;
        }
    }
}
TOP

Related Classes of com.facebook.presto.jdbc.internal.airlift.http.client.ApacheHttpClient$ExceptionFromResponseHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.