I'm using google-api-client-java 1.2.1-alpha to execute a POST request, and am getting the following stacktrace when I execute() the HttpRequest.
It happens immediately after I catch and ignore a 403 error from a previous POST to the same URL, and re-used the transport for the subsequent request. (It's in a loop inserting multiple entries to the same ATOM feed).
Is there something I should be doing to 'clean up' after a 403?
Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199)
at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:173)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:390)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
at com.google.api.client.apache.ApacheHttpRequest.execute(ApacheHttpRequest.java:47)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:207)
at au.com.machaira.pss.gape.RedirectHandler.execute(RedirectHandler.java:38)
at au.com.machaira.pss.gape.ss.model.records.TableEntry.executeModification(TableEntry.java:81)
Why would the code below me be trying to acquire a new connection?
You need to consume the response body before you can reuse the connection for another request. You should not only read the response status, but read the response InputStream
fully to the last byte whereby you just ignore the read bytes.
I was facing a similar issue when using the HttpClient with Jetty to build a test framework. I had to create multiple requests to the Servelet from my client, but It was giving the same exception when executed.
I found an alternative at http://foo.jasonhudgins.com/2010/03/http-connections-revisited.html
You can also use this following method to instantiate your client.
public static DefaultHttpClient getThreadSafeClient() {
DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
mgr.getSchemeRegistry()), params);
return client;
}
A similar exception message (since at least Apache Jarkata Commons HTTP Client 4.2) is:
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
This exception can happen when two or more threads interact with a single org.apache.http.impl.client.DefaultHttpClient
.
How can you make a 4.2 DefaultHttpClient
instance threadsafe (threadsafe in the sense that two or more threads can interact with it without getting above error message)? Provide DefaultHttpClient
with a connection-pooling ClientConnectionManager
in the form of org.apache.http.impl.conn.PoolingClientConnectionManager
!
/* using
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.2</version>
</dependency>
*/
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.HttpParams;
import org.apache.http.client.methods.HttpGet;
public class MyComponent {
private HttpClient client;
{
PoolingClientConnectionManager conMan = new PoolingClientConnectionManager( SchemeRegistryFactory.createDefault() );
conMan.setMaxTotal(200);
conMan.setDefaultMaxPerRoute(200);
client = new DefaultHttpClient(conMan);
//The following parameter configurations are not
//neccessary for this example, but they show how
//to further tweak the HttpClient
HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 20000);
HttpConnectionParams.setSoTimeout(params, 15000);
}
//This method can be called concurrently by several threads
private InputStream getResource(String uri) {
try {
HttpGet method = new HttpGet(uri);
HttpResponse httpResponse = client.execute(method);
int statusCode = httpResponse.getStatusLine().getStatusCode();
InputStream is = null;
if (HttpStatus.SC_OK == statusCode) {
logger.debug("200 OK Amazon request");
is = httpResponse.getEntity().getContent();
} else {
logger.debug("Something went wrong, statusCode is {}",
statusCode);
EntityUtils.consume(httpResponse.getEntity());
}
return is;
} catch (Exception e) {
logger.error("Something went terribly wrong", e);
throw new RuntimeException(e);
}
}
}
This is an often-asked question. BalusC's response is correct. Please catch HttpReponseException, and call HttpResponseException.response.ignore(). If you need to read the error message, use response.parseAsString() if you don't know the response content type, else if you do know the content type use response.parseAs(MyType.class).
A simple code snippet from YouTubeSample.java in youtube-jsonc-sample (though usually you'll want to do something smarter in a real application):
} catch (HttpResponseException e) {
System.err.println(e.response.parseAsString());
}
Full disclosure: I am an owner of the google-api-java-client project.
I had the same issue with a jax-rs (resteasy) Response
object in my unit tests.
I solved this with a call to response.releaseConnection();
The releaseConnection()-Method is only on the resteasy ClientResponse
object, so I had to add a cast from Response
to ClientResponse
.
Try this
HttpResponse response = Client.execute(httpGet);
response.getEntity().consumeContent();
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
//task
Log.i("Connection", "OK");
}else{
Log.i("Connection", "Down");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With