Package com.cloudseal.rest.client

Source Code of com.cloudseal.rest.client.RESTClientImpl$GzipRequestInterceptor

/* Copyright 2012 Cloudseal Ltd
*
* 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.cloudseal.rest.client;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.client.methods.HttpDelete;
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.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.protocol.HttpContext;

import com.cloudseal.rest.exception.RestException;
import org.apache.log4j.Logger;

/**
* Apache <a href="http://hc.apache.org/">Http Components</a> based
* implementation
*
* <p>
* This class supports connection pooling and GZIP compression. This
* implementation can reuse an existing HttpClient or create and manage it's own
* connection pool. <strong>Note:</strong> This class wraps all exceptions as
* unchecked RestExceptions so there is no need to explicitly catch them unless
* required.
* </p>
*
* <p>
* Logging is supported via <a href="http://logging.apache.org/log4j/1.2/">Log4J</a> at Error,
* Debug and Trace levels. This class is thread safe.
* </p>
*
* <p>
* Calling code should invoke the destroy method when finished to free up
* resources
* </p>
*
* @author Toby Hobson <a
*         href="mailto:toby.hobson@cloudseal.com">toby.hobson@cloudseal.com</a>
* @since 1.0
*
*
*/
public class RESTClientImpl implements RESTClient {

  private static final Logger LOG = Logger.getLogger(RESTClientImpl.class);

  private PoolingClientConnectionManager cm;
  private HttpClient httpClient;
  private String hostname;
  private String accessKey;
  private String secret;
  private JAXBContext jaxbContext;

  /**
   * Construct a new instance with a configurable thread/connection pool.
   *
   * @param hostname
   *            Cloudseal hostname e.g. acme
   * @param accessKey
   *            Access key (you can find this in your Cloudseal admin console)
   * @param secret
   *            Secret (you can find this in your Cloudseal admin cons
   * @param threadPool
   *            Thread/connection pool size
   * @param useGzip
   *            Whether the client should use GZIP compression.
   *
   */
  public RESTClientImpl(String hostname, String accessKey, String secret,
      int threadPool, boolean useGzip) {
    this.hostname = hostname;
    this.accessKey = accessKey;
    this.secret = secret;

    LOG.debug("Creating HTTP connection pool");
    cm = new PoolingClientConnectionManager();
    cm.setMaxTotal(threadPool);
        cm.setDefaultMaxPerRoute(threadPool);

    LOG.debug("Creating HTTP client");
    httpClient = new DefaultHttpClient(cm);

    if (useGzip) {
      LOG.debug("Adding GZIP support");
      addGzipInterceptors((DefaultHttpClient) httpClient);
    }

    try {
      LOG.debug("Creating JAXB marshaller/unmarshaller");
      jaxbContext = JAXBContext.newInstance("com.cloudseal.rest.jaxb");
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
  }

  /**
   * Construct a new instance using an existing HttpClient
   *
   * @param hostname
   *            Cloudseal hostname e.g. acme
   * @param accessKey
   *            Access key (you can find this in your Cloudseal admin console)
   * @param secret
   *            Secret (you can find this in your Cloudseal admin console)
   * @param httpClient
   *            Existing {@link org.apache.http.client.HttpClient} instance
   *
   */
  public RESTClientImpl(String hostname, String accessKey, String secret,
      HttpClient httpClient) {
    this.hostname = hostname;
    this.accessKey = accessKey;
    this.secret = secret;
    this.httpClient = httpClient;

    LOG.debug("Using existing HttpClient instance");

    try {
      LOG.debug("Creating JAXB marshaller/unmarshaller");
      jaxbContext = JAXBContext.newInstance("com.cloudseal.rest.jaxb");
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
  }

  /**
   * Construct a new instance using the defaults: Connection pool size of 10,
   * GZIP compression enabled
   *
   * @param hostname
   *            Cloudseal hostname e.g. acme
   * @param accessKey
   *            Access key (you can find this in your Cloudseal admin console)
   * @param secret
   *            Secret (you can find this in your Cloudseal admin console)
   */
  public RESTClientImpl(String hostname, String accessKey, String secret) {
    this(hostname, accessKey, secret, 10, true);
  }

  /**
   * Make a GET request for an object. This method will return a null object
   * in the event of a 404 error on the server end.
   *
   * @throws java.io.IOException
   *             In the event of an underlying connection problem
   * @throws org.apache.http.client.ClientProtocolException
   *             In the event of a 500 error on the server
   * @throws javax.xml.bind.JAXBException
   *             In the event that the HTTP response cannot be unmarshalled
   *
   * @see RESTClient#get(String)
   */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T get(String path) {
    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Invoking GET " + buildUrl(path));
      }

            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            ResponseHandler<String> responseHandler = new LoggingResponseHandlerDecorator();
      HttpGet get = new HttpGet(buildUrl(path));
      addHeaders(get);

            HttpResponse response = httpClient.execute(get);
      logResponse(response);
            String responseBody = responseHandler.handleResponse(response);

            if (response.getStatusLine().getStatusCode() == 404) {
        return null;
      }

      T object = (T) unmarshaller
          .unmarshal(new StringReader(responseBody));

      return object;
    } catch (ClientProtocolException ex) {
            if (ex.getMessage().equals("USER_NOT_FOUND")) {
                return null;
            } else {
          throw new RestException(ex);
            }
    } catch (IOException ex) {
      throw new RestException(ex);
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
        finally {

        }
  }

  /**
   * Make a POST request
   *
   * @throws java.io.IOException
   *             In the event of an underlying connection problem
   * @throws org.apache.http.client.ClientProtocolException
   *             In the event of a 500 error on the server
   * @throws javax.xml.bind.JAXBException
   *             In the event that the HTTP request or response cannot be
   *             marshalled/unmarshalled
   *
   * @see RESTClient#post
   */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T post(String path, T body) {
    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Invoking POST " + buildUrl(path));
      }

            Marshaller marshaller = jaxbContext.createMarshaller();
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

      StringWriter writer = new StringWriter();
      marshaller.marshal(body, writer);
      String xmlRequest = writer.toString();

      ResponseHandler<String> responseHandler = new LoggingResponseHandlerDecorator();
      HttpPost post = new HttpPost(buildUrl(path));
      addHeaders(post);

      post.setEntity(new StringEntity(xmlRequest));

      HttpResponse response = httpClient.execute(post);

      logResponse(response);

      String responseBody = responseHandler.handleResponse(response);
      T object = (T) unmarshaller
          .unmarshal(new StringReader(responseBody));
      return object;
    } catch (ClientProtocolException ex) {
      throw new RestException(ex);
    } catch (IOException ex) {
      throw new RestException(ex);
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
  }

  /**
   * Make a PUT request. This method will throw a wrapped
   * ClientProtocolException if the server returns a 404 error.
   *
   * @throws java.io.IOException
   *             In the event of an underlying connection problem
   * @throws org.apache.http.client.ClientProtocolException
   *             In the event of a 500 error on the server
   * @throws javax.xml.bind.JAXBException
   *             In the event that the HTTP response cannot be unmarshalled
   *
   * @see RESTClient#put
   */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T put(String path, T body) {
    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Invoking PUT " + buildUrl(path));
      }

            Marshaller marshaller = jaxbContext.createMarshaller();
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

      StringWriter writer = new StringWriter();
      marshaller.marshal(body, writer);
      String xmlRequest = writer.toString();

      ResponseHandler<String> responseHandler = new LoggingResponseHandlerDecorator();
      HttpPut put = new HttpPut(buildUrl(path));
      addHeaders(put);

      put.setEntity(new StringEntity(xmlRequest));

      HttpResponse response = httpClient.execute(put);

      logResponse(response);

      String responseBody = responseHandler.handleResponse(response);
      T object = (T) unmarshaller
          .unmarshal(new StringReader(responseBody));
      return object;
    } catch (ClientProtocolException ex) {
      throw new RestException(ex);
    } catch (IOException ex) {
      throw new RestException(ex);
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
  }

  /**
   * Make a DELETE request. This object will throw a wrapped
   * ClientProtocolException if the server returns a 404 error.
   *
   * @throws java.io.IOException
   *             In the event of an underlying connection problem
   * @throws org.apache.http.client.ClientProtocolException
   *             In the event of a 500 error on the server
   * @throws javax.xml.bind.JAXBException
   *             In the event that the HTTP response cannot be unmarshalled
   *
   * @see RESTClient#delete(String)
   */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T delete(String path) {
    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Invoking DELETE " + buildUrl(path));
      }

            Marshaller marshaller = jaxbContext.createMarshaller();
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

      ResponseHandler<String> responseHandler = new LoggingResponseHandlerDecorator();
      HttpDelete delete = new HttpDelete(buildUrl(path));
      addHeaders(delete);

      HttpResponse response = httpClient.execute(delete);

      logResponse(response);

      String responseBody = responseHandler.handleResponse(response);
      T object = (T) unmarshaller
          .unmarshal(new StringReader(responseBody));
      return object;
    } catch (ClientProtocolException ex) {
      throw new RestException(ex);
    } catch (IOException ex) {
      throw new RestException(ex);
    } catch (JAXBException ex) {
      throw new RestException(ex);
    }
  }

  /**
   * Shutdown the connection manager. This method must be called to ensure the
   * underlying resources are released.
   *
   */
  public void destroy() {
    if (cm != null) {
      cm.shutdown();
    }
  }

  private String buildUrl(String path) {
    StringBuilder builder = new StringBuilder();
    builder.append("https://");
    builder.append(hostname);
    builder.append(".cloudseal.com");
    builder.append(path);
    return builder.toString();
  }

  private void addHeaders(HttpRequestBase httpRequest) {
    httpRequest.setHeader("X-Access-Key", this.accessKey);
    httpRequest.setHeader("X-Secret", this.secret);
    httpRequest.setHeader("Host", hostname + ".cloudseal.com");
    httpRequest.setHeader("Accept", "application/xml");
    httpRequest.setHeader("Content-Type", "application/xml");
  }

  private void logResponse(HttpResponse response)
      throws HttpResponseException, IOException {
    if (LOG.isDebugEnabled()) {
      LOG.debug("Received response " + response.getStatusLine());
    }
  }

  private void addGzipInterceptors(DefaultHttpClient httpClient) {
    httpClient.addRequestInterceptor(new GzipRequestInterceptor());
    httpClient.addResponseInterceptor(new GzipResponseInterceptor());
  }

  private class LoggingResponseHandlerDecorator implements
      ResponseHandler<String> {
    private BasicResponseHandler delegate = new BasicResponseHandler();

    @Override
    public String handleResponse(HttpResponse response)
        throws ClientProtocolException, IOException {

      if (LOG.isTraceEnabled()) {
        for (Header header : response.getAllHeaders()) {
          LOG.trace("HTTP Response " + header.toString());
        }
      }

      String responseString = delegate.handleResponse(response);
      if (LOG.isTraceEnabled()) {
        LOG.debug("HTTP Response: \n" + responseString);
      }

      return responseString;
    }
  }

  private class GzipRequestInterceptor implements HttpRequestInterceptor {

    @Override
    public void process(final HttpRequest request, final HttpContext context)
        throws HttpException, IOException {
      if (!request.containsHeader("Accept-Encoding")) {
        request.addHeader("Accept-Encoding", "gzip");
      }
    }
  }

  private class GzipResponseInterceptor implements HttpResponseInterceptor {

    @Override
    public void process(HttpResponse response, HttpContext context)
        throws HttpException, IOException {
      HttpEntity entity = response.getEntity();
      Header ceheader = entity.getContentEncoding();
      if (ceheader != null) {
        HeaderElement[] codecs = ceheader.getElements();
        for (int i = 0; i < codecs.length; i++) {
          if (codecs[i].getName().equalsIgnoreCase("gzip")) {
            response.setEntity(new GzipDecompressingEntity(response
                .getEntity()));
            return;
          }
        }
      }
    }
  }

}
TOP

Related Classes of com.cloudseal.rest.client.RESTClientImpl$GzipRequestInterceptor

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.
reate', 'UA-20639858-1', 'auto'); ga('send', 'pageview');