Author: rvesse
Date: Fri Aug  9 17:30:40 2013
New Revision: 1512409

URL: http://svn.apache.org/r1512409
Log:
Take care to recycle HttpClient's created in QueryEngineHTTP (JENA-498)

Modified:
    
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
    
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java?rev=1512409&r1=1512408&r2=1512409&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
 (original)
+++ 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
 Fri Aug  9 17:30:40 2013
@@ -21,9 +21,11 @@ package com.hp.hpl.jena.sparql.engine.ht
 import java.io.InputStream ;
 import java.net.MalformedURLException ;
 import java.net.URL ;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern ;
 
 import org.apache.http.client.HttpClient ;
+import org.apache.http.conn.params.ConnManagerPNames;
 import org.apache.http.impl.client.AbstractHttpClient ;
 import org.apache.http.impl.client.DecompressingHttpClient ;
 import org.apache.http.impl.client.SystemDefaultHttpClient ;
@@ -73,6 +75,7 @@ public class HttpQuery extends Params {
     private int connectTimeout = 0, readTimeout = 0;
     private boolean allowGZip = false;
     private boolean allowDeflate = false;
+    private HttpClient client;
 
     // static final String ENC_UTF8 = "UTF-8" ;
 
@@ -191,6 +194,14 @@ public class HttpQuery extends Params {
     public void setAuthenticator(HttpAuthenticator authenticator) {
         this.authenticator = authenticator;
     }
+    
+    /**
+     * Gets the HTTP client that is being used, may be null if no request has 
yet been made
+     * @return HTTP Client or null
+     */
+    public HttpClient getClient() {
+        return this.client;
+    }
 
     /**
      * Return whether this request will go by GET or POST
@@ -271,6 +282,7 @@ public class HttpQuery extends Params {
         }
     }
 
+    @SuppressWarnings("deprecation")
     private InputStream execGet() throws QueryExceptionHTTP {
         URL target = null;
         String qs = getQueryString();
@@ -289,11 +301,19 @@ public class HttpQuery extends Params {
 
         try {
             try {
-                HttpClient client = new SystemDefaultHttpClient();
+                this.client = new SystemDefaultHttpClient();
+                
+                // Always apply a 10 second timeout to obtaining a connection 
lease from HTTP Client
+                // This prevents a potential lock up
+                
this.client.getParams().setLongParameter(ConnManagerPNames.TIMEOUT, 
TimeUnit.SECONDS.toMillis(10));
+                
+                // If user has specified time outs apply them now
                 if (this.connectTimeout > 0)
-                    
client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 
this.connectTimeout);
+                    
this.client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
 this.connectTimeout);
                 if (this.readTimeout > 0)
-                    
client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 
this.readTimeout);
+                    
this.client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 
this.readTimeout);
+                
+                // Enable compression support appropriately
                 HttpContext context = new BasicHttpContext();
                 if (allowGZip || allowDeflate) {
                     // Apply auth early as the decompressing client we're about
@@ -301,6 +321,8 @@ public class HttpQuery extends Params {
                     HttpOp.applyAuthentication((AbstractHttpClient) client, 
serviceURL, context, authenticator);
                     client = new DecompressingHttpClient(client);
                 }
+                
+                // Get the actual response stream
                 TypedInputStream stream = 
HttpOp.execHttpGet(target.toString(), contentTypeResult, client, context,
                         this.authenticator);
                 if (stream == null)
@@ -319,6 +341,7 @@ public class HttpQuery extends Params {
         }
     }
 
+    @SuppressWarnings("deprecation")
     private InputStream execPost() throws QueryExceptionHTTP {
         URL target = null;
         try {
@@ -331,19 +354,28 @@ public class HttpQuery extends Params {
         ARQ.getHttpRequestLogger().trace(target.toExternalForm());
 
         try {
-            HttpClient client = new SystemDefaultHttpClient();
+            this.client = new SystemDefaultHttpClient();
+            
+            // Always apply a 10 second timeout to obtaining a connection 
lease from HTTP Client
+            // This prevents a potential lock up
+            
this.client.getParams().setLongParameter(ConnManagerPNames.TIMEOUT, 
TimeUnit.SECONDS.toMillis(10));
+            
+            // If user has specified time outs apply them now
             if (this.connectTimeout > 0)
-                
client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 
this.connectTimeout);
+                
this.client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
 this.connectTimeout);
             if (this.readTimeout > 0)
-                
client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 
this.readTimeout);
+                
this.client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 
this.readTimeout);
+            
+            // Enable compression support appropriately
             HttpContext context = new BasicHttpContext();
             if (allowGZip || allowDeflate) {
                 // Apply auth early as the decompressing client we're about
                 // to add will block this being applied later
                 HttpOp.applyAuthentication((AbstractHttpClient) client, 
serviceURL, context, authenticator);
-                client = new DecompressingHttpClient(client);
+                this.client = new DecompressingHttpClient(client);
             }
 
+            // Get the actual response stream
             TypedInputStream stream = 
HttpOp.execHttpPostFormStream(serviceURL, this, contentTypeResult, client, 
context, authenticator);
             if (stream == null)
                 throw new QueryExceptionHTTP(404);

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java?rev=1512409&r1=1512408&r2=1512409&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java
 (original)
+++ 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java
 Fri Aug  9 17:30:40 2013
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.http.client.HttpClient;
 import org.apache.jena.atlas.io.IO;
 import org.apache.jena.atlas.web.auth.HttpAuthenticator;
 import org.apache.jena.atlas.web.auth.SimpleAuthenticator;
@@ -100,6 +101,8 @@ public class QueryEngineHTTP implements 
     // and will close when the engine is closed
     private InputStream retainedConnection = null;
 
+    private HttpClient retainedClient;
+
     public QueryEngineHTTP(String serviceURI, Query query) {
         this(serviceURI, query, query.toString());
     }
@@ -350,6 +353,7 @@ public class QueryEngineHTTP implements 
         }
 
         retainedConnection = in; // This will be closed on close()
+        retainedClient = httpQuery.getClient();
 
         // TODO: Find a way to auto-detect how to create the ResultSet based on
         // the content type in use
@@ -668,6 +672,15 @@ public class QueryEngineHTTP implements 
                 retainedConnection = null;
             }
         }
+        if (retainedClient != null) {
+            try {
+                retainedClient.getConnectionManager().shutdown();
+            } catch (RuntimeException e) {
+                log.warn("Failed to shutdown HTTP client", e);
+            } finally {
+                retainedClient = null;
+            }
+        }
     }
 
     // public boolean isActive() { return false ; }


Reply via email to