Package org.springframework.web.client

Source Code of org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback

/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.web.client;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.transform.Source;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.InterceptingHttpAccessor;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.util.UriTemplate;

/**
* <strong>Spring's central class for synchronous client-side HTTP access.</strong>
* It simplifies communication with HTTP servers, and enforces RESTful principles.
* It handles HTTP connections, leaving application code to provide URLs
* (with possible template variables) and extract results.
*
* <p>The main entry points of this template are the methods named after the six main HTTP methods:
* <table>
* <tr><th>HTTP method</th><th>RestTemplate methods</th></tr>
* <tr><td>DELETE</td><td>{@link #delete}</td></tr>
* <tr><td>GET</td><td>{@link #getForObject}</td></tr>
* <tr><td></td><td>{@link #getForEntity}</td></tr>
* <tr><td>HEAD</td><td>{@link #headForHeaders}</td></tr>
* <tr><td>OPTIONS</td><td>{@link #optionsForAllow}</td></tr>
* <tr><td>POST</td><td>{@link #postForLocation}</td></tr>
* <tr><td></td><td>{@link #postForObject}</td></tr>
* <tr><td>PUT</td><td>{@link #put}</td></tr>
* <tr><td>any</td><td>{@link #exchange}</td></tr>
* <tr><td></td><td>{@link #execute}</td></tr> </table>
*
* <p>In addition the {@code exchange} and {@code execute} methods are generalized versions of
* the above methods and can be used to support additional, less frequent combinations (e.g.
* HTTP PATCH, HTTP PUT with response body, etc.). Note however that the underlying HTTP
* library used must also support the desired combination.
*
* <p>For each HTTP method there are 3 variants -- two accept a URI template string
* and URI variables (array or map) while a third accepts a {@link URI}.
* Note that for URI templates it is assumed encoding is necessary, e.g.
* {@code restTemplate.getForObject("http://example.com/hotel list")} becomes
* {@code "http://example.com/hotel%20list"}. This also means if the URI template
* or URI variables are already encoded, double encoding will occur, e.g.
* {@code http://example.com/hotel%20list} becomes
* {@code http://example.com/hotel%2520list}). To avoid that use a {@code URI} method
* variant to provide (or re-use) a previously encoded URI. To prepare such an URI
* with full control over encoding, consider using
* {@link org.springframework.web.util.UriComponentsBuilder}.
*
* <p>Internally the template uses {@link HttpMessageConverter} instances to
* convert HTTP messages to and from POJOs. Converters for the main mime types
* are registered by default but you can also register additional converters
* via {@link #setMessageConverters}.
*
* <p>This template uses a
* {@link org.springframework.http.client.SimpleClientHttpRequestFactory} and a
* {@link DefaultResponseErrorHandler} as default strategies for creating HTTP
* connections or handling HTTP errors, respectively. These defaults can be overridden
* through {@link #setRequestFactory} and {@link #setErrorHandler} respectively.
*
* @author Arjen Poutsma
* @author Brian Clozel
* @author Roy Clarkson
* @since 3.0
* @see HttpMessageConverter
* @see RequestCallback
* @see ResponseExtractor
* @see ResponseErrorHandler
* @see AsyncRestTemplate
*/
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

  private static boolean romePresent =
      ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", RestTemplate.class.getClassLoader());

  private static final boolean jaxb2Present =
      ClassUtils.isPresent("javax.xml.bind.Binder", RestTemplate.class.getClassLoader());

  private static final boolean jackson2Present =
      ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", RestTemplate.class.getClassLoader()) &&
          ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", RestTemplate.class.getClassLoader());

  private static final boolean jackson2XmlPresent =
      ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", RestTemplate.class.getClassLoader());

  private static final boolean gsonPresent =
      ClassUtils.isPresent("com.google.gson.Gson", RestTemplate.class.getClassLoader());


  private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();

  private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();

  private final ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();


  /**
   * Create a new instance of the {@link RestTemplate} using default settings.
   * Default {@link HttpMessageConverter}s are initialized.
   */
  public RestTemplate() {
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(new StringHttpMessageConverter());
    this.messageConverters.add(new ResourceHttpMessageConverter());
    this.messageConverters.add(new SourceHttpMessageConverter<Source>());
    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

    if (romePresent) {
      this.messageConverters.add(new AtomFeedHttpMessageConverter());
      this.messageConverters.add(new RssChannelHttpMessageConverter());
    }
    if (jackson2XmlPresent) {
      messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
    }
    else if (jaxb2Present) {
      this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    }
    if (jackson2Present) {
      this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
      this.messageConverters.add(new GsonHttpMessageConverter());
    }
  }

  /**
   * Create a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}.
   * @param requestFactory HTTP request factory to use
   * @see org.springframework.http.client.SimpleClientHttpRequestFactory
   * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory
   */
  public RestTemplate(ClientHttpRequestFactory requestFactory) {
    this();
    setRequestFactory(requestFactory);
  }

  /**
   * Create a new instance of the {@link RestTemplate} using the given list of
   * {@link HttpMessageConverter} to use
   * @param messageConverters the list of {@link HttpMessageConverter} to use
   * @since 3.2.7
   */
  public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
    Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
    this.messageConverters.addAll(messageConverters);
  }


  /**
   * Set the message body converters to use.
   * <p>These converters are used to convert from and to HTTP requests and responses.
   */
  public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
    // Take getMessageConverters() List as-is when passed in here
    if (this.messageConverters != messageConverters) {
      this.messageConverters.clear();
      this.messageConverters.addAll(messageConverters);
    }
  }

  /**
   * Return the message body converters.
   */
  public List<HttpMessageConverter<?>> getMessageConverters() {
    return this.messageConverters;
  }

  /**
   * Set the error handler.
   * <p>By default, RestTemplate uses a {@link DefaultResponseErrorHandler}.
   */
  public void setErrorHandler(ResponseErrorHandler errorHandler) {
    Assert.notNull(errorHandler, "'errorHandler' must not be null");
    this.errorHandler = errorHandler;
  }

  /**
   * Return the error handler.
   */
  public ResponseErrorHandler getErrorHandler() {
    return this.errorHandler;
  }


  // GET

  @Override
  public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
  }

  @Override
  public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
  }

  @Override
  public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
  }

  @Override
  public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables)
      throws RestClientException {

    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
  }

  @Override
  public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables)
      throws RestClientException {

    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
  }

  @Override
  public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
  }


  // HEAD

  @Override
  public HttpHeaders headForHeaders(String url, Object... urlVariables) throws RestClientException {
    return execute(url, HttpMethod.HEAD, null, headersExtractor(), urlVariables);
  }

  @Override
  public HttpHeaders headForHeaders(String url, Map<String, ?> urlVariables) throws RestClientException {
    return execute(url, HttpMethod.HEAD, null, headersExtractor(), urlVariables);
  }

  @Override
  public HttpHeaders headForHeaders(URI url) throws RestClientException {
    return execute(url, HttpMethod.HEAD, null, headersExtractor());
  }


  // POST

  @Override
  public URI postForLocation(String url, Object request, Object... urlVariables) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), urlVariables);
    return headers.getLocation();
  }

  @Override
  public URI postForLocation(String url, Object request, Map<String, ?> urlVariables) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), urlVariables);
    return headers.getLocation();
  }

  @Override
  public URI postForLocation(URI url, Object request) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor());
    return headers.getLocation();
  }

  @Override
  public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
        new HttpMessageConverterExtractor<T>(responseType, getMessageConverters());
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
  }

  @Override
  public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
      throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
  }


  // PUT

  @Override
  public void put(String url, Object request, Object... urlVariables) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    execute(url, HttpMethod.PUT, requestCallback, null, urlVariables);
  }

  @Override
  public void put(String url, Object request, Map<String, ?> urlVariables) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    execute(url, HttpMethod.PUT, requestCallback, null, urlVariables);
  }

  @Override
  public void put(URI url, Object request) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(request);
    execute(url, HttpMethod.PUT, requestCallback, null);
  }


  // DELETE

  @Override
  public void delete(String url, Object... urlVariables) throws RestClientException {
    execute(url, HttpMethod.DELETE, null, null, urlVariables);
  }

  @Override
  public void delete(String url, Map<String, ?> urlVariables) throws RestClientException {
    execute(url, HttpMethod.DELETE, null, null, urlVariables);
  }

  @Override
  public void delete(URI url) throws RestClientException {
    execute(url, HttpMethod.DELETE, null, null);
  }


  // OPTIONS

  @Override
  public Set<HttpMethod> optionsForAllow(String url, Object... urlVariables) throws RestClientException {
    ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
    HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, urlVariables);
    return headers.getAllow();
  }

  @Override
  public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> urlVariables) throws RestClientException {
    ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
    HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, urlVariables);
    return headers.getAllow();
  }

  @Override
  public Set<HttpMethod> optionsForAllow(URI url) throws RestClientException {
    ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
    HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor);
    return headers.getAllow();
  }


  // exchange

  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
      HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, method, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
      HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, method, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
      Class<T> responseType) throws RestClientException {

    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(url, method, requestCallback, responseExtractor);
  }

  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
      ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {

    Type type = responseType.getType();
    RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
    return execute(url, method, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
      ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException {

    Type type = responseType.getType();
    RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
    return execute(url, method, requestCallback, responseExtractor, uriVariables);
  }

  @Override
  public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
      ParameterizedTypeReference<T> responseType) throws RestClientException {

    Type type = responseType.getType();
    RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
    return execute(url, method, requestCallback, responseExtractor);
  }

  @Override
  public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType)
      throws RestClientException {

    Assert.notNull(requestEntity, "'requestEntity' must not be null");

    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor);
  }

  @Override
  public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
      throws RestClientException {

    Assert.notNull(requestEntity, "'requestEntity' must not be null");

    Type type = responseType.getType();
    RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
    return execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor);
  }


  // general execution

  @Override
  public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
      ResponseExtractor<T> responseExtractor, Object... urlVariables) throws RestClientException {

    URI expanded = new UriTemplate(url).expand(urlVariables);
    return doExecute(expanded, method, requestCallback, responseExtractor);
  }

  @Override
  public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
      ResponseExtractor<T> responseExtractor, Map<String, ?> urlVariables) throws RestClientException {

    URI expanded = new UriTemplate(url).expand(urlVariables);
    return doExecute(expanded, method, requestCallback, responseExtractor);
  }

  @Override
  public <T> T execute(URI url, HttpMethod method, RequestCallback requestCallback,
      ResponseExtractor<T> responseExtractor) throws RestClientException {

    return doExecute(url, method, requestCallback, responseExtractor);
  }

  /**
   * Execute the given method on the provided URI.
   * <p>The {@link ClientHttpRequest} is processed using the {@link RequestCallback};
   * the response with the {@link ResponseExtractor}.
   * @param url the fully-expanded URL to connect to
   * @param method the HTTP method to execute (GET, POST, etc.)
   * @param requestCallback object that prepares the request (can be {@code null})
   * @param responseExtractor object that extracts the return value from the response (can be {@code null})
   * @return an arbitrary object, as returned by the {@link ResponseExtractor}
   */
  protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
      ResponseExtractor<T> responseExtractor) throws RestClientException {

    Assert.notNull(url, "'url' must not be null");
    Assert.notNull(method, "'method' must not be null");
    ClientHttpResponse response = null;
    try {
      ClientHttpRequest request = createRequest(url, method);
      if (requestCallback != null) {
        requestCallback.doWithRequest(request);
      }
      response = request.execute();
      if (!getErrorHandler().hasError(response)) {
        logResponseStatus(method, url, response);
      }
      else {
        handleResponseError(method, url, response);
      }
      if (responseExtractor != null) {
        return responseExtractor.extractData(response);
      }
      else {
        return null;
      }
    }
    catch (IOException ex) {
      throw new ResourceAccessException("I/O error on " + method.name() +
          " request for \"" + url + "\":" + ex.getMessage(), ex);
    }
    finally {
      if (response != null) {
        response.close();
      }
    }
  }

  private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
    if (logger.isDebugEnabled()) {
      try {
        logger.debug(method.name() + " request for \"" + url + "\" resulted in " +
            response.getRawStatusCode() + " (" + response.getStatusText() + ")");
      }
      catch (IOException e) {
        // ignore
      }
    }
  }

  private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
    if (logger.isWarnEnabled()) {
      try {
        logger.warn(method.name() + " request for \"" + url + "\" resulted in " +
            response.getRawStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
      }
      catch (IOException e) {
        // ignore
      }
    }
    getErrorHandler().handleError(response);
  }

  /**
   * Returns a request callback implementation that prepares the request {@code Accept}
   * headers based on the given response type and configured
   * {@linkplain #getMessageConverters() message converters}.
   */
  protected <T> RequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
    return new AcceptHeaderRequestCallback(responseType);
  }

  /**
   * Returns a request callback implementation that writes the given object to the
   * request stream.
   */
  protected <T> RequestCallback httpEntityCallback(Object requestBody) {
    return new HttpEntityRequestCallback(requestBody);
  }

  /**
   * Returns a request callback implementation that writes the given object to the
   * request stream.
   */
  protected <T> RequestCallback httpEntityCallback(Object requestBody, Type responseType) {
    return new HttpEntityRequestCallback(requestBody, responseType);
  }

  /**
   * Returns a response extractor for {@link ResponseEntity}.
   */
  protected <T> ResponseExtractor<ResponseEntity<T>> responseEntityExtractor(Type responseType) {
    return new ResponseEntityResponseExtractor<T>(responseType);
  }

  /**
   * Returns a response extractor for {@link HttpHeaders}.
   */
  protected ResponseExtractor<HttpHeaders> headersExtractor() {
    return this.headersExtractor;
  }


  /**
   * Request callback implementation that prepares the request's accept headers.
   */
  private class AcceptHeaderRequestCallback implements RequestCallback {

    private final Type responseType;

    private AcceptHeaderRequestCallback(Type responseType) {
      this.responseType = responseType;
    }

    @Override
    public void doWithRequest(ClientHttpRequest request) throws IOException {
      if (responseType != null) {
        Class<?> responseClass = null;
        if (responseType instanceof Class) {
          responseClass = (Class<?>) responseType;
        }

        List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
        for (HttpMessageConverter<?> converter : getMessageConverters()) {
          if (responseClass != null) {
            if (converter.canRead(responseClass, null)) {
              allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter));
            }
          }
          else if (converter instanceof GenericHttpMessageConverter) {

            GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
            if (genericConverter.canRead(responseType, null, null)) {
              allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter));
            }
          }

        }
        if (!allSupportedMediaTypes.isEmpty()) {
          MediaType.sortBySpecificity(allSupportedMediaTypes);
          if (logger.isDebugEnabled()) {
            logger.debug("Setting request Accept header to " +
                allSupportedMediaTypes);
          }
          request.getHeaders().setAccept(allSupportedMediaTypes);
        }
      }
    }

    private List<MediaType> getSupportedMediaTypes(HttpMessageConverter<?> messageConverter) {
      List<MediaType> supportedMediaTypes = messageConverter.getSupportedMediaTypes();
      List<MediaType> result = new ArrayList<MediaType>(supportedMediaTypes.size());
      for (MediaType supportedMediaType : supportedMediaTypes) {
        if (supportedMediaType.getCharSet() != null) {
          supportedMediaType =
              new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype());
        }
        result.add(supportedMediaType);
      }
      return result;
    }
  }


  /**
   * Request callback implementation that writes the given object to the request stream.
   */
  private class HttpEntityRequestCallback extends AcceptHeaderRequestCallback {

    private final HttpEntity<?> requestEntity;

    private HttpEntityRequestCallback(Object requestBody) {
      this(requestBody, null);
    }

    private HttpEntityRequestCallback(Object requestBody, Type responseType) {
      super(responseType);
      if (requestBody instanceof HttpEntity) {
        this.requestEntity = (HttpEntity<?>) requestBody;
      }
      else if (requestBody != null) {
        this.requestEntity = new HttpEntity<Object>(requestBody);
      }
      else {
        this.requestEntity = HttpEntity.EMPTY;
      }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
      super.doWithRequest(httpRequest);
      if (!requestEntity.hasBody()) {
        HttpHeaders httpHeaders = httpRequest.getHeaders();
        HttpHeaders requestHeaders = requestEntity.getHeaders();
        if (!requestHeaders.isEmpty()) {
          httpHeaders.putAll(requestHeaders);
        }
        if (httpHeaders.getContentLength() == -1) {
          httpHeaders.setContentLength(0L);
        }
      }
      else {
        Object requestBody = requestEntity.getBody();
        Class<?> requestType = requestBody.getClass();
        HttpHeaders requestHeaders = requestEntity.getHeaders();
        MediaType requestContentType = requestHeaders.getContentType();
        for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {
          if (messageConverter.canWrite(requestType, requestContentType)) {
            if (!requestHeaders.isEmpty()) {
              httpRequest.getHeaders().putAll(requestHeaders);
            }
            if (logger.isDebugEnabled()) {
              if (requestContentType != null) {
                logger.debug("Writing [" + requestBody + "] as \"" + requestContentType +
                    "\" using [" + messageConverter + "]");
              }
              else {
                logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
              }

            }
            ((HttpMessageConverter<Object>) messageConverter).write(
                requestBody, requestContentType, httpRequest);
            return;
          }
        }
        String message = "Could not write request: no suitable HttpMessageConverter found for request type [" +
            requestType.getName() + "]";
        if (requestContentType != null) {
          message += " and content type [" + requestContentType + "]";
        }
        throw new RestClientException(message);
      }
    }
  }


  /**
   * Response extractor for {@link HttpEntity}.
   */
  private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {

    private final HttpMessageConverterExtractor<T> delegate;

    public ResponseEntityResponseExtractor(Type responseType) {
      if (responseType != null && !Void.class.equals(responseType)) {
        this.delegate = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
      }
      else {
        this.delegate = null;
      }
    }

    @Override
    public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
      if (this.delegate != null) {
        T body = this.delegate.extractData(response);
        return new ResponseEntity<T>(body, response.getHeaders(), response.getStatusCode());
      }
      else {
        return new ResponseEntity<T>(response.getHeaders(), response.getStatusCode());
      }
    }
  }


  /**
   * Response extractor that extracts the response {@link HttpHeaders}.
   */
  private static class HeadersExtractor implements ResponseExtractor<HttpHeaders> {

    @Override
    public HttpHeaders extractData(ClientHttpResponse response) throws IOException {
      return response.getHeaders();
    }
  }

}
TOP

Related Classes of org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback

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.