How to set a HTTP timeout when retrieving RDF from a URI? - java

I am resolving RDF URIs in a Servlet using Jena:
final Model rdfModel = ModelFactory.createDefaultModel();
rdfModel.read(resource);
Is there a possibility to set Http Connect and Socket timeouts in Jena?
Or is it the only option to do handle the http connection 'manually' using Apache HttpClient?
final HttpClient httpclient = new DefaultHttpClient();
final HttpParams params = httpclient.getParams();
params.setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, 1000);
params.setParameter(HttpConnectionParams.SO_TIMEOUT, 5000);
...

Here's the code based on #rob-hall's hint:
final Model rdfModel = ModelFactory.createDefaultModel();
final HttpClient httpclient = new DefaultHttpClient();
final HttpParams params = httpclient.getParams();
params.setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, 1000);
params.setParameter(HttpConnectionParams.SO_TIMEOUT, 5000);
HttpOp.setDefaultHttpClient(httpclient);
rdfModel.read(resource);

From the design of the API, it appears that you should be able to use HttpOp#setDefaultHttpClient() to modify the default HttpClient utilized within Jena.
HttpOp#execHttpGet(String,String) is delegated to by LocatorURL#open(String), which is called by the StreamManager used by RDFDataMgr. Elsewhere, HttpOp#ensureClient(...) substitutes in the default client, if it is present.

Related

How to register AuthSchemes on HttpClient

I have this code
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm",new NTLMSchemeFactory());
However eclipse says that DefaultHttpClient is deprecated and I replaced this with
HttpClient client = HttpClientBuilder.create().build();
However now I have no api called getAuthSchemes(). So Now with this new class, how do I register the auth scheme?
I also found
ArrayList<String> authPrefs = new ArrayList<String>(2);
authPrefs.add(AuthSchemes.KERBEROS);
client.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authPrefs);
but here also getParams and AuthPNames are deprecated.
So what is the non-deprecated way of setting Authentication Schemes.
Configuration is not longer done in the client but in the request, after you have your HttpPost (or HttpGet, or whatever) and before calling execute() do this:
HttpPost post = new HttpPost(...);
ArrayList<String> authPrefs = new ArrayList<String>();
authPrefs.add(AuthSchemes.NTLM);
authPrefs.add(AuthSchemes.KERBEROS);
// ...
RequestConfig config = RequestConfig.custom()
.setProxyPreferredAuthSchemes(authPrefs).build();
post.setConfig(config);
// ....
client.execute(post);
To expand on morgano's answer, here is a quick deprecation conversion for those who are using NTLMTransport and ksoap2 to authenticate in a Windows Authentication/NTLM environment (I'm using httpclient-4.3.1, and httpcore-4.3 as dependancies, but other jars should work as long as they're >= 4.3).
Remove
DefaultHttpClient client = new DefaultHttpClient();
Replace with
public static HttpPost httppost;
public static HttpClient client;
in your "call" method, replace any HttpPost and redefine your "client" before you setHeaders
//....
httppost = new HttpPost(url);
client = HttpClientBuilder.create().build();
ArrayList<String> authPrefs = new ArrayList<String>();
authPrefs.add(AuthSchemes.NTLM);
authPrefs.add(AuthSchemes.KERBEROS);
RequestConfig config = RequestConfig.custom().setProxyPreferredAuthSchemes(authPrefs).build();
httppost.setConfig(config);
//....
then in your setupNtlm method, remove getAuthSchemes
client.getAuthSchemes().register("ntlm",new NTLMSchemeFactory());
and add the authPrefs to your HttpGet (key here is that the HttpPost and HttpGet needed to config the authPrefs before client.execute)
HttpGet httpget = new HttpGet(url);
ArrayList<String> authPrefs = new ArrayList<String>();
authPrefs.add(AuthSchemes.NTLM);
authPrefs.add(AuthSchemes.KERBEROS);
RequestConfig config = RequestConfig.custom().setProxyPreferredAuthSchemes(authPrefs).build();
httpget.setConfig(config);
It looks like there are still some deprecated functions like HttpEntity.consumeContent(), but the above changes worked for me when compiling for API 23.

Is the ProxyFactory replacement in RESTEasy thread safe?

I developed a service in RESTEasy using ProxyFactory and ClientExecutor like this:
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 5000);
ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient);
MyClass client = ProxyFactory.create(MyClass.class, "http://www.example.com", clientExecutor);
It always worked perfectly. After RESTEasy deprecated both ClientExecutor and ProxyFactory, they provided a new ResteasyClient for external connections, but I don't know if this new ResteasyClient is threadsafe. This is the new sample code from the documentation:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://example.com/base/uri");
SimpleClient simple = target.proxy(SimpleClient.class);
UPDATE: I used the code with the ResteasyClient and I got many of these errors:
javax.ws.rs.ProcessingException: Unable to invoke request
Caused by
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.
We use this:
final ResteasyClient client = new ResteasyClientBuilder()
.connectionPoolSize(10)
.maxPooledPerRoute(5)
.build();
And after debugging I found out that (at least in our situation) the RESTEasy client uses the ThreadSafeClientConnManager by default so I think there is no need to specify a different one although according to the JavaDoc it is deprecated in favour of PoolingHttpClientConnectionManager (note the extra Http). But this has been fixed in RESTEasy client 3.0.5.Final: https://issues.jboss.org/browse/RESTEASY-948
It's a jungle of HTTP connection managers out there..
This worked for me. Just needed to find the hook into setting up the Apache HTTP engine. Mostly based on RestEasy 3.0.5.Final API
public static Object setupServiceProxy(#NotNull Class responseClass) {
ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance();
ResteasyClientBuilder builder = new ResteasyClientBuilder().providerFactory(factory);
ResteasyClient client = builder.httpEngine(setupHttpDefaults()).build();
ResteasyWebTarget target = client.target(url);
return target.proxy(responseClass);
}
public static ClientHttpEngine setupHttpDefaults() {
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 30000);
HttpConnectionParams.setSoTimeout(params, 30000);
BasicHttpContext localContext = new BasicHttpContext();
return new ApacheHttpClient4Engine(httpClient, localContext);
}

Trying to add a http parameter but it isn't working

HttpClient httpclient = new DefaultHttpClient();
try {
HttpPost httpMethod = new HttpPost(this.transformURL(request));
BasicHttpParams params = new BasicHttpParams();
params.setParameter("name", name);
httpMethod.setParams(params);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpclient.execute(httpMethod, responseHandler);
}catch{
LOG.error("Error");
} finally {
httpclient.getConnectionManager().shutdown();
}
I have the above code, and I'm trying to pass in a name variable as a paramter to get picked up in another method by request.getParameter("name").
It doesn't seem to be working, when I debug I can see the parameters get set but when I follow it through to the next method that gets executed, it doesn't pick up the parameters.
Any suggestions?
EDIT:
I added this and it worked great
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("name", request.getParameter("name")));
httpMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
Did you check this example? it uses the class BasicNameValuePair instead of BasicHttpParams as you do.
Also, the documentation for the version 3.x of HttpClient does it:
PostMethod post = new PostMethod("http://jakarata.apache.org/");
NameValuePair[] data = {
new NameValuePair("user", "joe"),
new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
// execute method and handle any error responses.
...
InputStream in = post.getResponseBodyAsStream();
// handle response.
Update: The BasicHttpParams class is an implementation of the HttpParams interface, which as #Perception notes below, is a set of properties "that customize the behavior of the HTTP client". From the HttpParams javadoc: "HttpParams is expected to be used in 'write once - read many' mode. Once initialized, HTTP parameters are not expected to mutate in the course of HTTP message processing."

Apache HttpComponents HttpClient timeout

How do I set the connection timeout in httpcomponents httpclient? I have found the documentation at: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html but it is not clear how these parameters are actually set.
Also, an explanation of the difference between SO_TIMEOUT and CONNECTION_TIMEOUT would be helpful.
In version 4.3 of Apache Http Client the configuration was refactored (again). The new way looks like this:
RequestConfig.Builder requestBuilder = RequestConfig.custom();
requestBuilder.setConnectTimeout(timeout);
requestBuilder.setConnectionRequestTimeout(timeout);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
HttpClient client = builder.build();
In HttpClient 4.3 version you can use below example.. let say for 5 seconds
int timeout = 5;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpGet request = new HttpGet("http://localhost:8080/service"); // GET Request
response = client.execute(request);
The answer from #jontro is correct, but it's always nice to have a code snippet on how to do this. There are two ways to do this:
Version 1: Set a 10 second timeout for each of these parameters:
HttpClient httpclient = new DefaultHttpClient();
// this one causes a timeout if a connection is established but there is
// no response within 10 seconds
httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 10 * 1000);
// this one causes a timeout if no connection is established within 10 seconds
httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10 * 1000);
// now do the execute:
HttpGet httpget = new HttpGet(URL);
HttpResponse response = httpclient.execute(httpget);
Version 2: Also set a 10 second timeout for each of these parameters:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 10 * 1000);
HttpConnectionParams.setSoTimeout(params, 10 * 1000);
HttpClient httpclient = new DefaultHttpClient(params);
HttpGet httpget = new HttpGet(URL);
HttpResponse response = httpclient.execute(httpget);
In section 2.5 you see an example of how to set the CONNECTION_TIMEOUT parameter.
CONNECTION_TIMEOUT is the time waiting for the initial connection and SO_TIMEOUT is the timeout that you wait for when reading a packet after the connection is established.
I set a hard timeout for the entire request to workaround the java.net.SocketInputStream.socketRead0 problem.
private static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newSingleThreadScheduledExecutor()
HttpGet request = new HttpGet("http://www.example.com")
final Runnable delayedTask = new Runnable() {
#Override
public void run() {
request.abort()
}
}
SCHEDULED_EXECUTOR.schedule(delayedTask, 100000, TimeUnit.MILLISECONDS)

HttpClient - setting a "global" socket timeout, and a separate timeout per request

With HttpClient, I am setting the default socket/connection timeout with the following:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setSoTimeout(params, 30000);
HttpConnectionParams.setConnectionTimeout(params, 30000);
mClient = new DefaultHttpClient(connectionManager, params);
I'm wondering if I can override these values on a per request basis?
Edit: Would this work?
HttpParams params = req.getParams(); // req is an HttpRequest object
HttpConnectionParams.setSoTimeout(params, 60000);
HttpConnectionParams.setConnectionTimeout(params, 60000);
I tried it, and it seems to, but it's hard to test/create a situation where a timeout will occur.
If you are using HttpClient 4.0 you could do this :
mClient = new DefaultHttpClient(connectionManager, params) {
protected HttpParams determineParams(HttpRequest req) {
//Fill in your impl here
}
You can simply set those parameters on the request object. For details see:
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e391

Categories