All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartsheet.api.internal.http.DefaultHttpClient Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
package com.smartsheet.api.internal.http;

/*
 * #[license]
 * Smartsheet SDK for Java
 * %%
 * Copyright (C) 2014 Smartsheet
 * %%
 * 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.
 * %[license]
 */

import com.smartsheet.api.Trace;
import com.smartsheet.api.internal.util.Util;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
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.HttpRequestWrapper;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * This is the Apache HttpClient (http://hc.apache.org/httpcomponents-client-ga/index.html) based HttpClient
 * implementation.
 *
 * Thread Safety: This class is thread safe because it is immutable and the underlying Apache CloseableHttpClient is
 * thread safe.
 */
public class DefaultHttpClient implements HttpClient {
    /** logger for general errors, warnings, etc */
    private static final Logger logger = LoggerFactory.getLogger(DefaultHttpClient.class);

    // to avoid creating new sets for each call (we use Sets for practical and perf reasons)
    private static final Set REQUEST_RESPONSE_SUMMARY = Collections.unmodifiableSet(new HashSet(
            Arrays.asList(Trace.RequestHeaders, Trace.RequestBodySummary, Trace.ResponseHeaders, Trace.ResponseBodySummary)));

    // default values for trace-logging extracted from system-properties (can still be overwritten at the instance level)
    private static final boolean TRACE_PRETTY_PRINT_DEFAULT = Boolean.parseBoolean(System.getProperty("Smartsheet.trace.pretty", "true"));

    private static final Set TRACE_DEFAULT_TRACE_SET  = Trace.parse(System.getProperty("Smartsheet.trace.parts"));    // empty by default

    /** where to send trace logs */
    private static PrintWriter TRACE_WRITER;
    static {
        setTraceStream(System.out); // default trace stream
        if (TRACE_DEFAULT_TRACE_SET.size() > 0) {
            TRACE_WRITER.println("default trace logging - pretty:" + TRACE_PRETTY_PRINT_DEFAULT + " parts:" + TRACE_DEFAULT_TRACE_SET);
        }
    }

    /**
     * Represents the underlying Apache CloseableHttpClient.
     * 

* It will be initialized in constructor and will not change afterwards. */ private final CloseableHttpClient httpClient; /** The apache http request. */ private HttpRequestBase apacheHttpRequest; /** The apache http response. */ private CloseableHttpResponse apacheHttpResponse; /** UserAgent string sent with each request */ private final String userAgent; /** the set of Trace levels to use in trace-logging */ private final Set traces = new HashSet(TRACE_DEFAULT_TRACE_SET); /** whether to log pretty or compact */ private boolean tracePrettyPrint = TRACE_PRETTY_PRINT_DEFAULT; @Deprecated // never used (within SDK) public static final String USER_AGENT = "Mozilla/5.0 Firefox/26.0"; /** * Constructor. */ public DefaultHttpClient() { this(HttpClients.createDefault()); } /** * Constructor. *

* Parameters: - httpClient : the Apache CloseableHttpClient to use *

* Exceptions: - IllegalArgumentException : if any argument is null * * @param httpClient the http client */ public DefaultHttpClient(CloseableHttpClient httpClient) { this.httpClient = Util.throwIfNull(httpClient); this.userAgent = generateUserAgent(getClass()); } /** * Make an HTTP request and return the response. * * @param smartsheetRequest the smartsheet request * @return the HTTP response * @throws HttpClientException the HTTP client exception */ public HttpResponse request(HttpRequest smartsheetRequest) throws HttpClientException { Util.throwIfNull(smartsheetRequest); if (smartsheetRequest.getUri() == null) { throw new IllegalArgumentException("A Request URI is required."); } // Create Apache HTTP request based on the smartsheetRequest request type switch (smartsheetRequest.getMethod()) { case GET: apacheHttpRequest = new HttpGet(smartsheetRequest.getUri()); break; case POST: apacheHttpRequest = new HttpPost(smartsheetRequest.getUri()); break; case PUT: apacheHttpRequest = new HttpPut(smartsheetRequest.getUri()); break; case DELETE: apacheHttpRequest = new HttpDelete(smartsheetRequest.getUri()); break; default: throw new UnsupportedOperationException("Request method " + smartsheetRequest.getMethod() + " is not supported!"); } RequestConfig.Builder builder = RequestConfig.custom(); if (apacheHttpRequest.getConfig() != null) { builder = RequestConfig.copy(apacheHttpRequest.getConfig()); } builder.setRedirectsEnabled(true); RequestConfig config = builder.build(); apacheHttpRequest.setConfig(config); // Set HTTP headers if (smartsheetRequest.getHeaders() != null) { for (Map.Entry header : smartsheetRequest.getHeaders().entrySet()) { apacheHttpRequest.addHeader(header.getKey(), header.getValue()); } } // Set User Agent apacheHttpRequest.setHeader(HttpHeaders.USER_AGENT, userAgent); HttpEntity originalRequestEntity = null; HttpEntity originalResponseEntity = null; // Set HTTP entity final HttpEntity entity = smartsheetRequest.getEntity(); if (apacheHttpRequest instanceof HttpEntityEnclosingRequestBase && entity != null && entity.getContent() != null) { try { // we need access to the original request stream so we can log it (in the event of errors and/or tracing) originalRequestEntity = new HttpEntity(entity); } catch (IOException iox) { logger.error("failed to make copy of original request entity - {}", iox); } InputStreamEntity streamEntity = new InputStreamEntity(entity.getContent(), entity.getContentLength()); streamEntity.setChunked(false); // why? not supported by library? ((HttpEntityEnclosingRequestBase) apacheHttpRequest).setEntity(streamEntity); } // Make the HTTP request HttpResponse smartsheetResponse = new HttpResponse(); HttpContext context = new BasicHttpContext(); try { apacheHttpResponse = this.httpClient.execute(apacheHttpRequest, context); // Set request headers to values ACTUALLY SENT (not just created by us) HttpRequestWrapper actualRequest = (HttpRequestWrapper)context.getAttribute("http.request"); if (actualRequest != null) { apacheHttpRequest.setHeaders(actualRequest.getAllHeaders()); } // Set returned headers smartsheetResponse.setHeaders(new HashMap()); for (Header header : apacheHttpResponse.getAllHeaders()) { smartsheetResponse.getHeaders().put(header.getName(), header.getValue()); } smartsheetResponse.setStatus(apacheHttpResponse.getStatusLine().getStatusCode(), apacheHttpResponse.getStatusLine().toString()); // Set returned entities if (apacheHttpResponse.getEntity() != null) { HttpEntity httpEntity = new HttpEntity(); httpEntity.setContentType(apacheHttpResponse.getEntity().getContentType().getValue()); httpEntity.setContentLength(apacheHttpResponse.getEntity().getContentLength()); httpEntity.setContent(apacheHttpResponse.getEntity().getContent()); smartsheetResponse.setEntity(httpEntity); originalResponseEntity = new HttpEntity(httpEntity); } // HTTP-error logging if (smartsheetResponse.getStatusCode() != 200) { // log the summary request and response on error logger.warn("{}", RequestAndResponseData.of(apacheHttpRequest, originalRequestEntity, smartsheetResponse, originalResponseEntity, REQUEST_RESPONSE_SUMMARY)); } if (traces.size() > 0) { // trace-logging of request and response (if so configured) RequestAndResponseData requestAndResponseData = RequestAndResponseData.of(apacheHttpRequest, originalRequestEntity, smartsheetResponse, originalResponseEntity, traces); TRACE_WRITER.println(requestAndResponseData.toString(tracePrettyPrint)); } } catch (ClientProtocolException e) { try { logger.warn("{}", RequestAndResponseData.of(apacheHttpRequest, originalRequestEntity, smartsheetResponse, originalResponseEntity, REQUEST_RESPONSE_SUMMARY)); } catch (IOException ignore) {} throw new HttpClientException("Error occurred.", e); } catch (IOException e) { try { logger.warn("{}", RequestAndResponseData.of(apacheHttpRequest, originalRequestEntity, smartsheetResponse, originalResponseEntity, REQUEST_RESPONSE_SUMMARY)); } catch (IOException ignore) {} throw new HttpClientException("Error occurred.", e); } return smartsheetResponse; } /** * Close the HttpClient. * * @throws IOException Signals that an I/O exception has occurred. */ @Override public void close() throws IOException { this.httpClient.close(); } /* (non-Javadoc) * @see com.smartsheet.api.internal.http.HttpClient#releaseConnection() */ @Override public void releaseConnection() { if (apacheHttpResponse != null) { try { apacheHttpResponse.close(); apacheHttpResponse = null; } catch (IOException e) { logger.error("error closing Apache HttpResponse - {}", e); } } } @Override public void setTraces(Trace... traces) { this.traces.clear(); for (Trace trace : traces) { if (!trace.addReplacements(this.traces)) { this.traces.add(trace); } } } @Override public void setTracePrettyPrint(boolean pretty) { tracePrettyPrint = pretty; } /** only included for testing purposes */ public static void setTraceStream(OutputStream traceStream) { TRACE_WRITER = new PrintWriter(traceStream, true); } /** * * @param clazz the Class used to find the Package (depends on the jar MANIFEST from which this class was loaded) * @return a User-Agent string that represents this version of the SDK (along with platform info) */ static String generateUserAgent(Class clazz) { String thisVersion = ""; String title = ""; Package thisPackage = clazz.getPackage(); if (thisPackage != null) { thisVersion = thisPackage.getImplementationVersion(); title = thisPackage.getImplementationTitle(); } return title + "/" + thisVersion + " " + System.getProperty("os.name") + " " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vendor") + " " + System.getProperty("java.version"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy