You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/02/02 00:05:44 UTC

svn commit: r905439 - in /incubator/shindig/trunk: ./ java/common/src/main/java/org/apache/shindig/common/cache/ java/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/samples/ java/social-api/ java/social-api/src/main/java/org/...

Author: lindner
Date: Mon Feb  1 23:05:43 2010
New Revision: 905439

URL: http://svn.apache.org/viewvc?rev=905439&view=rev
Log:
httpclient 4.0 upgrade

Modified:
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/cache/LruCacheProvider.java
    incubator/shindig/trunk/java/gadgets/pom.xml
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
    incubator/shindig/trunk/java/samples/pom.xml
    incubator/shindig/trunk/java/social-api/pom.xml
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/service/SampleContainerHandler.java
    incubator/shindig/trunk/pom.xml

Modified: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/cache/LruCacheProvider.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/cache/LruCacheProvider.java?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/cache/LruCacheProvider.java (original)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/cache/LruCacheProvider.java Mon Feb  1 23:05:43 2010
@@ -84,12 +84,12 @@
   public <K, V> Cache<K, V> createCache(String name) {
     int capacity = getCapacity(name);
     if (name == null) {
-      LOG.info("Creating anonymous cache");
+      LOG.fine("Creating anonymous cache");
       return new LruCache<K, V>(capacity);
     } else {
       Cache<K, V> cache = (Cache<K, V>) caches.get(name);
       if (cache == null) {
-        LOG.info("Creating cache named " + name);
+        LOG.fine("Creating cache named " + name);
         cache = new LruCache<K, V>(capacity);
         caches.put(name, cache);
       }

Modified: incubator/shindig/trunk/java/gadgets/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/pom.xml (original)
+++ incubator/shindig/trunk/java/gadgets/pom.xml Mon Feb  1 23:05:43 2010
@@ -143,7 +143,7 @@
     </dependency>
     <dependency>
       <groupId>net.oauth.core</groupId>
-      <artifactId>oauth-httpclient3</artifactId>
+      <artifactId>oauth-httpclient4</artifactId>
     </dependency>
     <dependency>
       <groupId>com.google.collections</groupId>
@@ -208,8 +208,9 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>commons-httpclient</groupId>
-      <artifactId>commons-httpclient</artifactId>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <version>4.0.1</version>
     </dependency>
 
     <!-- test -->

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java Mon Feb  1 23:05:43 2010
@@ -17,259 +17,386 @@
  */
 package org.apache.shindig.gadgets.http;
 
-import com.google.inject.internal.Preconditions;
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.DeleteMethod;
-import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.PutMethod;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.io.output.ByteArrayOutputStream;
-import org.apache.shindig.common.uri.Uri;
-
-import com.google.common.collect.Maps;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import com.google.inject.internal.Preconditions;
 import com.google.inject.name.Named;
 
-import java.io.ByteArrayInputStream;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.NoHttpResponseException;
+import org.apache.http.client.HttpClient;
+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.HttpHead;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.conn.params.ConnManagerParams;
+import org.apache.http.conn.params.ConnPerRouteBean;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.HttpEntityWrapper;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
 import java.net.ProxySelector;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
 /**
- * A very primitive HTTP fetcher implementation. Not recommended for production deployments until
+ * A simple HTTP fetcher implementation based on Apache httpclient. Not recommended for production deployments until
  * the following issues are addressed:
- *
+ * <p/>
  * 1. This class potentially allows access to resources behind an organization's firewall.
- * 2. This class does not handle most advanced HTTP functionality correctly (SSL, etc.)
- * 3. This class does not enforce any limits on what is fetched from remote hosts.
+ * 2. This class does not enforce any limits on what is fetched from remote hosts.
  */
 @Singleton
 public class BasicHttpFetcher implements HttpFetcher {
   private static final int DEFAULT_CONNECT_TIMEOUT_MS = 5000;
+  private static final int DEFAULT_READ_TIMEOUT_MS = 5000;
   private static final int DEFAULT_MAX_OBJECT_SIZE = 0;  // no limit
-  private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+  private static final long DEFAULT_SLOW_RESPONSE_WARNING = 10000;
+
+  protected final HttpClient FETCHER;
 
   // mutable fields must be volatile
-  private volatile int maxObjSize; 
-  private volatile int connectionTimeoutMs;
+  private volatile int maxObjSize;
+  private volatile long slowResponseWarning;
 
-  /**
-   * Creates a new fetcher for fetching HTTP objects.  Not really suitable
-   * for production use. Use of an HTTP proxy for security is also necessary
-   * for production deployment.
-   *
-   * @param maxObjSize Maximum size, in bytes, of the object we will fetch, 0 if no limit..
-   * @param connectionTimeoutMs timeout, in milliseconds, for requests.
-   */
-  public BasicHttpFetcher(int maxObjSize, int connectionTimeoutMs) {
-    setMaxObjectSizeBytes(maxObjSize);
-	  setConnectionTimeoutMs(connectionTimeoutMs);
-  }
+  private static final Logger LOG = Logger.getLogger(BasicHttpFetcher.class.getName());
+
+  private final Set<Class<?>> TIMEOUT_EXCEPTIONS = ImmutableSet.<Class<?>>of(ConnectionPoolTimeoutException.class,
+      SocketTimeoutException.class, SocketException.class, HttpHostConnectException.class, NoHttpResponseException.class,
+      InterruptedException.class, UnknownHostException.class);
 
   /**
    * Creates a new fetcher using the default maximum object size and timeout --
    * no limit and 5 seconds.
    */
   public BasicHttpFetcher() {
-    this(DEFAULT_MAX_OBJECT_SIZE, DEFAULT_CONNECT_TIMEOUT_MS);
+    this(DEFAULT_MAX_OBJECT_SIZE, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
   }
 
-  /**
-   * Change the global maximum fetch size (in bytes) for all fetches. 
-   *
-   * @param maxObjectSizeBytes value for maximum number of bytes, or 0 for no limit
-   */
-  @Inject(optional = true)
-  public void setMaxObjectSizeBytes(@Named("shindig.http.client.max-object-size-bytes") int maxObjectSizeBytes) {
-    this.maxObjSize = maxObjectSizeBytes;
+  @Deprecated
+  public BasicHttpFetcher(int maxObjSize, int connectionTimeoutMs) {
+    this(maxObjSize, connectionTimeoutMs, DEFAULT_READ_TIMEOUT_MS);
   }
 
   /**
-   * Change the global connection timeout for all fetchs.
+   * Creates a new fetcher for fetching HTTP objects.  Not really suitable
+   * for production use. Use of an HTTP proxy for security is also necessary
+   * for production deployment.
    *
-   * @param connectionTimeoutMs new connection timeout in milliseconds
+   * @param maxObjSize          Maximum size, in bytes, of the object we will fetch, 0 if no limit..
+   * @param connectionTimeoutMs timeout, in milliseconds, for connecting to hosts.
+   * @param readTimeoutMs       timeout, in millseconds, for unresponsive connections
    */
-  @Inject(optional = true)
-  public void setConnectionTimeoutMs(@Named("shindig.http.client.connection-timeout-ms") int connectionTimeoutMs) {
-    Preconditions.checkArgument(connectionTimeoutMs > 0, "connection-timeout-ms must be greater than 0");
-    this.connectionTimeoutMs = connectionTimeoutMs;
-  }
+  public BasicHttpFetcher(int maxObjSize, int connectionTimeoutMs, int readTimeoutMs) {
+    // Create and initialize HTTP parameters
+    setMaxObjectSizeBytes(maxObjSize);
+    setSlowResponseWarning(DEFAULT_SLOW_RESPONSE_WARNING);
 
-  /**
-   * @param httpMethod
-   * @param responseCode
-   * @return A HttpResponse object made by consuming the response of the
-   *     given HttpMethod.
-   * @throws java.io.IOException
-   */
-  private HttpResponse makeResponse(HttpMethod httpMethod, int responseCode) throws IOException {
-    Map<String, String> headers = Maps.newHashMap();
+    HttpParams params = new BasicHttpParams();
+
+    ConnManagerParams.setTimeout(params, connectionTimeoutMs);
+
+    // These are probably overkill for most sites.
+    ConnManagerParams.setMaxTotalConnections(params, 1152);
+    ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(256));
 
-    if (httpMethod.getResponseHeaders() != null) {
-      for (Header h : httpMethod.getResponseHeaders()) {
-        headers.put(h.getName(), h.getValue());
+    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+    HttpProtocolParams.setUserAgent(params, "Apache Shindig");
+    HttpProtocolParams.setContentCharset(params, "UTF-8");
+
+    HttpConnectionParams.setConnectionTimeout(params, connectionTimeoutMs);
+    HttpConnectionParams.setSoTimeout(params, readTimeoutMs);
+    HttpConnectionParams.setStaleCheckingEnabled(params, true);
+
+    HttpClientParams.setRedirecting(params, true);
+    HttpClientParams.setAuthenticating(params, false);
+
+    // Create and initialize scheme registry
+    SchemeRegistry schemeRegistry = new SchemeRegistry();
+    schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+    schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
+
+    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
+
+    DefaultHttpClient client = new DefaultHttpClient(cm, params);
+
+    // try resending the request once
+    client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(1, true));
+
+    // Add hooks for gzip/deflate
+    client.addRequestInterceptor(new HttpRequestInterceptor() {
+      public void process(
+          final org.apache.http.HttpRequest request,
+          final HttpContext context) throws HttpException, IOException {
+        if (!request.containsHeader("Accept-Encoding")) {
+          request.addHeader("Accept-Encoding", "gzip, deflate");
+        }
       }
-    }
+    });
+    client.addResponseInterceptor(new HttpResponseInterceptor() {
+      public void process(
+          final org.apache.http.HttpResponse response,
+          final HttpContext context) throws HttpException, IOException {
+        HttpEntity entity = response.getEntity();
+        if (entity != null) {
+          Header ceheader = entity.getContentEncoding();
+          if (ceheader != null) {
+            for (HeaderElement codec : ceheader.getElements()) {
+              String codecname = codec.getName();
+              if ("gzip".equalsIgnoreCase(codecname)) {
+                response.setEntity(
+                    new GzipDecompressingEntity(response.getEntity()));
+                return;
+              } else if ("deflate".equals(codecname)) {
+                response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
+                return;
+              }
+            }
+          }
+        }
+      }
+    });
+    client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler() );
 
-    // The first header is always null here to provide the response body.
-    headers.remove(null);
+    // Use Java's built-in proxy logic
+    ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
+            client.getConnectionManager().getSchemeRegistry(),
+            ProxySelector.getDefault());
+    client.setRoutePlanner(routePlanner);
 
-    // Find the response stream - the error stream may be valid in cases
-    // where the input stream is not.
-    InputStream responseBodyStream = null;
-    try {
-      responseBodyStream = httpMethod.getResponseBodyAsStream();
-    } catch (IOException e) {
-      // normal for 401, 403 and 404 responses, for example...
-    }
+    FETCHER = client;
+  }
 
-    if (responseBodyStream == null) {
-      // Fall back to zero length response.
-      responseBodyStream = new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY);
+  static class GzipDecompressingEntity extends HttpEntityWrapper {
+    public GzipDecompressingEntity(final HttpEntity entity) {
+      super(entity);
     }
 
-    String encoding = headers.get("Content-Encoding");
+    public InputStream getContent() throws IOException, IllegalStateException {
+      // the wrapped entity's getContent() decides about repeatability
+      InputStream wrappedin = wrappedEntity.getContent();
 
-    // Create the appropriate stream wrapper based on the encoding type.
-    InputStream is = responseBodyStream;
-    if (encoding == null) {
-      is = responseBodyStream;
-    } else if (encoding.equalsIgnoreCase("gzip")) {
-      is = new GZIPInputStream(responseBodyStream);
-    } else if (encoding.equalsIgnoreCase("deflate")) {
-      Inflater inflater = new Inflater(true);
-      is = new InflaterInputStream(responseBodyStream, inflater);
+      return new GZIPInputStream(wrappedin);
     }
 
-    ByteArrayOutputStream output = new ByteArrayOutputStream();
-    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
-    int totalBytesRead = 0;
-    int currentBytesRead;
-
-    while ((currentBytesRead = is.read(buffer)) != -1) {
-      output.write(buffer, 0, currentBytesRead);
-      totalBytesRead += currentBytesRead;
-
-      if(maxObjSize > 0 && totalBytesRead > maxObjSize) {
-        IOUtils.closeQuietly(is);
-        IOUtils.closeQuietly(output);
-        // Exceeded max # of bytes
-        return HttpResponse.badrequest("Exceeded maximum number of bytes - " + this.maxObjSize);
-      }
+    public long getContentLength() {
+      // length of ungzipped content is not known
+      return -1;
     }
-
-    return new HttpResponseBuilder()
-        .setHttpStatusCode(responseCode)
-        .setResponse(output.toByteArray())
-        .addHeaders(headers)
-        .create();
   }
 
-  /** {@inheritDoc} */
-  public HttpResponse fetch(HttpRequest request) {
-    HttpClient httpClient = new HttpClient();
-    HttpMethod httpMethod;
-    String methodType = request.getMethod();
-    String requestUri = request.getUri().toString();
-
-    // Select a proxy based on the URI. May be Proxy.NO_PROXY
-    Proxy proxy = ProxySelector.getDefault().select(request.getUri().toJavaUri()).get(0);
-
-    if (proxy != Proxy.NO_PROXY) {
-      InetSocketAddress address = (InetSocketAddress) proxy.address();
-      httpClient.getHostConfiguration().setProxy(address.getHostName(), address.getPort());
+  static class DeflateDecompressingEntity extends HttpEntityWrapper {
+    public DeflateDecompressingEntity(final HttpEntity entity) {
+      super(entity);
     }
 
+    public InputStream getContent()
+        throws IOException, IllegalStateException {
 
-    // true for non-HEAD requests
-    boolean requestCompressedContent = true;
+      // the wrapped entity's getContent() decides about repeatability
+      InputStream wrappedin = wrappedEntity.getContent();
 
-    if ("POST".equals(methodType) || "PUT".equals(methodType)) {
-      EntityEnclosingMethod enclosingMethod = ("POST".equals(methodType))
-              ? new PostMethod(requestUri)
-              : new PutMethod(requestUri);
-
-      if (request.getPostBodyLength() > 0) {
-        enclosingMethod.setRequestEntity(new InputStreamRequestEntity(request.getPostBody()));
-        enclosingMethod.setRequestHeader("Content-Length",
-            String.valueOf(request.getPostBodyLength()));
-      }
-      httpMethod = enclosingMethod;
-    } else if ("DELETE".equals(methodType)) {
-      httpMethod = new DeleteMethod(requestUri);
-    } else if ("HEAD".equals(methodType)) {
-      httpMethod = new HeadMethod(requestUri);
-    } else {
-      httpMethod = new GetMethod(requestUri);
+      return new InflaterInputStream(wrappedin, new Inflater(true));
     }
 
-    httpMethod.setFollowRedirects(false);
-    httpMethod.getParams().setSoTimeout(connectionTimeoutMs);
+    public long getContentLength() {
+      // length of ungzipped content is not known
+      return -1;
+    }
+  }
 
-    if (requestCompressedContent)
-      httpMethod.setRequestHeader("Accept-Encoding", "gzip, deflate");
+  public HttpResponse fetch(org.apache.shindig.gadgets.http.HttpRequest request) {
+    HttpUriRequest httpMethod = null;
+    Preconditions.checkNotNull(request);
+    final String methodType = request.getMethod();
+    final String requestUri = request.getUri().toString();
 
-    for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
-      httpMethod.setRequestHeader(entry.getKey(), StringUtils.join(entry.getValue(), ','));
-    }
+    final org.apache.http.HttpResponse response;
+    final long started = System.currentTimeMillis();
 
     try {
+      if ("POST".equals(methodType) || "PUT".equals(methodType)) {
+        HttpEntityEnclosingRequestBase enclosingMethod = ("POST".equals(methodType))
+          ? new HttpPost(requestUri)
+          : new HttpPut(requestUri);
+
+        if (request.getPostBodyLength() > 0) {
+          enclosingMethod.setEntity(new InputStreamEntity(request.getPostBody(), request.getPostBodyLength()));
+        }
+        httpMethod = enclosingMethod;
+      } else if ("GET".equals(methodType)) {
+        httpMethod = new HttpGet(requestUri);
+      } else if ("HEAD".equals(methodType)) {
+        httpMethod = new HttpHead(requestUri);
+      } else if ("DELETE".equals(methodType)) {
+        httpMethod = new HttpDelete(requestUri);
+      }
+      for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
+        httpMethod.addHeader(entry.getKey(), StringUtils.join(entry.getValue(), ','));
+      }
 
-      int statusCode = httpClient.executeMethod(httpMethod);
+      if (!request.getFollowRedirects())
+        httpMethod.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
+      
+      response = FETCHER.execute(httpMethod);
 
-      // Handle redirects manually
-      if (request.getFollowRedirects() &&
-          ((statusCode == HttpStatus.SC_MOVED_TEMPORARILY) ||
-          (statusCode == HttpStatus.SC_MOVED_PERMANENTLY) ||
-          (statusCode == HttpStatus.SC_SEE_OTHER) ||
-          (statusCode == HttpStatus.SC_TEMPORARY_REDIRECT))) {
-
-        Header header = httpMethod.getResponseHeader("location");
-        if (header != null) {
-            String redirectUri = header.getValue();
+      if (response == null)
+        throw new IOException("Unknown problem with request");
 
-            if ((redirectUri == null) || (redirectUri.equals(""))) {
-                redirectUri = "/";
-            }
-            // Url can be relative to original:
-            redirectUri = request.getUri().resolve(Uri.parse(redirectUri)).toString();
-            
-            httpMethod.releaseConnection();
-            httpMethod = new GetMethod(redirectUri);
+      if (response.getEntity() == null) {
+        throw new IOException("Cannot retrieve " + request.getUri() + " reason " + response.getStatusLine().getReasonPhrase());
+      }
 
-            statusCode = httpClient.executeMethod(httpMethod);
-        }
+      long now = System.currentTimeMillis();
+      if (now - started > slowResponseWarning) {
+        slowResponseWarning(request, started, now);
       }
 
-      return makeResponse(httpMethod, statusCode);
+      return makeResponse(response);
 
-    } catch (IOException e) {
-      if (e instanceof java.net.SocketTimeoutException ||
-          e instanceof java.net.SocketException) {
+    } catch (Exception e) {
+      long now = System.currentTimeMillis();
+
+      // Find timeout exceptions, respond accordingly
+      if (TIMEOUT_EXCEPTIONS.contains(e.getClass())) {
+        LOG.warning("Timeout for " + request.getUri() + " Exception: " + e.getClass().getName() + " - " + e.getMessage() + " - " + (now - started) + "ms");
         return HttpResponse.timeout();
       }
 
-      return HttpResponse.error();
+      LOG.log(Level.WARNING, "Got Exception fetching " + request.getUri() + " - " + (now - started) + "ms", e);
 
+      return HttpResponse.error();
     } finally {
-      httpMethod.releaseConnection();
+      // cleanup any outstanding resources..
+      if (httpMethod != null) try {
+        httpMethod.abort();
+      } catch (Exception e) {
+        // ignore
+      }
+    }
+  }
+
+  /**
+   * Called when a request takes too long.   Consider subclassing this if you want to do something other than logging
+   * a warning .
+   *
+   * @param request the request that generated the slowrequest
+   * @param started  the time the request started, in milliseconds.
+   * @param finished the time the request finished, in milliseconds.
+   */
+  protected void slowResponseWarning(HttpRequest request, long started, long finished) {
+    LOG.warning("Slow response from " + request.getUri() + ' ' + (finished - started) + "ms");
+  }
+
+  /**
+   * Change the global maximum fetch size (in bytes) for all fetches.
+   *
+   * @param maxObjectSizeBytes value for maximum number of bytes, or 0 for no limit
+   */
+  @Inject(optional = true)
+  public void setMaxObjectSizeBytes(@Named("shindig.http.client.max-object-size-bytes") int maxObjectSizeBytes) {
+    this.maxObjSize = maxObjectSizeBytes;
+  }
+
+  /**
+   * Change the global threshold for warning about slow responses
+   *
+   * @param slowResponseWarning time in milliseconds after we issue a warning
+   */
+
+  @Inject(optional = true)
+  public void setSlowResponseWarning(@Named("shindig.http.client.slow-response-warning") long slowResponseWarning) {
+    this.slowResponseWarning = slowResponseWarning;
+  }
+
+  /**
+   * Change the global connection timeout for all new fetchs.
+   *
+   * @param connectionTimeoutMs new connection timeout in milliseconds
+   */
+  @Inject(optional = true)
+  public void setConnectionTimeoutMs(@Named("shindig.http.client.connection-timeout-ms") int connectionTimeoutMs) {
+    Preconditions.checkArgument(connectionTimeoutMs > 0, "connection-timeout-ms must be greater than 0");
+    FETCHER.getParams().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, connectionTimeoutMs);
+  }
+
+  /**
+   * Change the global read timeout for all new fetchs.
+   *
+   * @param connectionTimeoutMs new connection timeout in milliseconds
+   */
+  @Inject(optional = true)
+  public void setReadTimeoutMs(@Named("shindig.http.client.read-timeout-ms") int connectionTimeoutMs) {
+    Preconditions.checkArgument(connectionTimeoutMs > 0, "connection-timeout-ms must be greater than 0");
+    FETCHER.getParams().setIntParameter(HttpConnectionParams.SO_TIMEOUT, connectionTimeoutMs);
+  }
+
+
+  /**
+   * @param response The response to parse
+   * @return A HttpResponse object made by consuming the response of the
+   *         given HttpMethod.
+   * @throws IOException when problems occur processing the body content
+   */
+  private HttpResponse makeResponse(org.apache.http.HttpResponse response) throws IOException {
+    HttpResponseBuilder builder = new HttpResponseBuilder();
+
+    if (response.getAllHeaders() != null) {
+      for (Header h : response.getAllHeaders()) {
+        if (h.getName() != null)
+          builder.addHeader(h.getName(), h.getValue());
+      }
     }
+
+    HttpEntity entity = Preconditions.checkNotNull(response.getEntity());
+
+    if (maxObjSize > 0 && entity.getContentLength() > maxObjSize) {
+      return HttpResponse.badrequest("Exceeded maximum number of bytes - " + maxObjSize);
+    }
+
+    return builder
+        .setHttpStatusCode(response.getStatusLine().getStatusCode())
+        .setResponse(EntityUtils.toByteArray(entity))
+        .create();
   }
 }

Modified: incubator/shindig/trunk/java/samples/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/samples/pom.xml?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/samples/pom.xml (original)
+++ incubator/shindig/trunk/java/samples/pom.xml Mon Feb  1 23:05:43 2010
@@ -142,7 +142,7 @@
     </dependency>
     <dependency>
       <groupId>net.oauth.core</groupId>
-      <artifactId>oauth-httpclient3</artifactId>
+      <artifactId>oauth-httpclient4</artifactId>
     </dependency>
 
     <!-- Hibernate -->

Modified: incubator/shindig/trunk/java/social-api/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/pom.xml?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/pom.xml (original)
+++ incubator/shindig/trunk/java/social-api/pom.xml Mon Feb  1 23:05:43 2010
@@ -59,6 +59,12 @@
       <groupId>org.apache.shindig</groupId>
       <artifactId>shindig-common</artifactId>
     </dependency>
+
+      <dependency>
+        <groupId>org.apache.shindig</groupId>
+        <artifactId>shindig-gadgets</artifactId>
+      </dependency>
+
     <dependency>
       <groupId>org.apache.shindig</groupId>
       <artifactId>shindig-common</artifactId>
@@ -99,7 +105,7 @@
     </dependency>
     <dependency>
       <groupId>net.oauth.core</groupId>
-      <artifactId>oauth-httpclient3</artifactId>
+      <artifactId>oauth-httpclient4</artifactId>
     </dependency>
 
     <!-- may only be needed for JDK < 1.6 -->
@@ -124,8 +130,8 @@
       <artifactId>commons-io</artifactId>
     </dependency>
     <dependency>
-      <groupId>commons-httpclient</groupId>
-      <artifactId>commons-httpclient</artifactId>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
     </dependency>
     <dependency>
       <groupId>xml-apis</groupId>

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/service/SampleContainerHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/service/SampleContainerHandler.java?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/service/SampleContainerHandler.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/service/SampleContainerHandler.java Mon Feb  1 23:05:43 2010
@@ -18,10 +18,8 @@
 
 package org.apache.shindig.social.sample.service;
 
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.shindig.common.util.ImmediateFuture;
+import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.protocol.Operation;
 import org.apache.shindig.protocol.ProtocolException;
 import org.apache.shindig.protocol.RequestItem;
@@ -29,6 +27,11 @@
 import org.apache.shindig.social.sample.spi.JsonDbOpensocialService;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpFetcher;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
+
 
 import java.io.IOException;
 import java.util.concurrent.Future;
@@ -42,10 +45,11 @@
 public class SampleContainerHandler {
 
   private final JsonDbOpensocialService service;
-
+  private final HttpFetcher fetcher;
   @Inject
-  public SampleContainerHandler(JsonDbOpensocialService dbService) {
+  public SampleContainerHandler(JsonDbOpensocialService dbService, HttpFetcher fetcher) {
     this.service = dbService;
+    this.fetcher = fetcher;
   }
 
   /**
@@ -93,19 +97,14 @@
     String errorMessage = "The json state file " + stateFileLocation
         + " could not be fetched and parsed.";
 
-    HttpMethod jsonState = new GetMethod(stateFileLocation);
-    HttpClient client = new HttpClient();
     try {
-      client.executeMethod(jsonState);
-
-      if (jsonState.getStatusCode() != 200) {
+      HttpResponse response = fetcher.fetch(new HttpRequest(Uri.parse(stateFileLocation)));
+      if (response.getHttpStatusCode() != 200) {
         throw new RuntimeException(errorMessage);
       }
-      return jsonState.getResponseBodyAsString();
-    } catch (IOException e) {
+      return response.getResponseAsString();
+    } catch (GadgetException e) {
       throw new RuntimeException(errorMessage, e);
-    } finally {
-      jsonState.releaseConnection();
     }
   }
 }

Modified: incubator/shindig/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/pom.xml?rev=905439&r1=905438&r2=905439&view=diff
==============================================================================
--- incubator/shindig/trunk/pom.xml (original)
+++ incubator/shindig/trunk/pom.xml Mon Feb  1 23:05:43 2010
@@ -1385,7 +1385,7 @@
       </dependency>
       <dependency>
         <groupId>net.oauth.core</groupId>
-        <artifactId>oauth-httpclient3</artifactId>
+        <artifactId>oauth-httpclient4</artifactId>
         <version>20090531</version>
         <scope>compile</scope>
       </dependency>
@@ -1524,9 +1524,9 @@
         <version>1.3.04</version>
       </dependency>
       <dependency>
-        <groupId>commons-httpclient</groupId>
-        <artifactId>commons-httpclient</artifactId>
-        <version>3.1</version>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpclient</artifactId>
+        <version>4.0.1</version>
       </dependency>
       <dependency>
         <groupId>org.jsecurity</groupId>