1

In httpclient 4.3, if you respect all the deprecations, you must build and configure your HttpClient using an HttpClientBuilder (documentation here). The methods are explicit, they seem easy to use, and HttpClient's interface is clear. But maybe a tad too much.

In my own case, I have to inherit Spring's HttpComponentsHttpInvokerRequestExecutor (documentation here). As a consequence, I can easily get the HttpClient, but all I know about this object is that it implements the interface.

Since the client is already built, and I do not know anything about its implementation, I cannot access methods such as AbstractHttpClient's setHttpRequestRetryHandler or addRequestInterceptor (though yes, I know, they are deprecated).

So, what would be the cleanest way of updating the settings of this HttpClient (the retry handler and request interceptor are those I am most concerned with at the moment)? Should I...

  • ... savagely cast my client to AbstractHttpClient, hoping I will always receive this implementation?
  • ... create a new HttpClient in my HttpInvokerRequestExecutor's constructor, and get something like the example reproduced below? I might add that Spring's constructor (in 3.2.4 at least) uses methods deprecated in httpclient 4.3 too. Would there be any side effect I missed using this strategy?
  • ... do something I have not proposed yet?

Custom constructor example:

public CustomHttpInvokerRequestExecutor() {
    super(); // will create an HttpClient
    // Now overwrite the client the super constructor created
    setHttpClient(HttpClientBuilder.custom(). ... .build());
}
Chop
  • 4,267
  • 5
  • 26
  • 58

1 Answers1

3

do something I have not proposed yet?

My recommendation would be to re-think the entire approach. One should not be removing / adding protocol interceptors at runtime but rather should be making use of HttpContext instance to update request execution context and pass configuration to protocol interceptors

http://hc.apache.org/httpcomponents-core-4.4.x/tutorial/html/fundamentals.html#d5e306 http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/fundamentals.html#d5e223

CloseableHttpClient client = HttpClientBuilder.create()
        .addInterceptorFirst(new HttpRequestInterceptor() {
            @Override
            public void process(
                    final HttpRequest request,
                    final HttpContext context) throws HttpException, IOException {
                boolean b = (Boolean) context.getAttribute("my-config");
                if (b) {
                    // do something useful
                }

            }
        })
        .build();
HttpClientContext context = HttpClientContext.create();
context.setAttribute("my-config", Boolean.TRUE);
CloseableHttpResponse response1 = client.execute(new HttpGet("/"), context);
response1.close();
context.setAttribute("my-config", Boolean.FALSE);
CloseableHttpResponse response2 = client.execute(new HttpGet("/"), context);
response2.close();
ok2c
  • 26,450
  • 5
  • 63
  • 71
  • I did not think of interceptors myself. This is actually a migration from httpclient3 to httpclient4, and in certain cases, I need preemptive authentication. Many examples I have found use an Interceptor to this ([an example](http://stackoverflow.com/questions/2014700/preemptive-basic-authentication-with-apache-httpclient-4)). Moreover, since I override another class, I only have access to the arguments passed to my super methods, which do not include the context. I tried finding it inside objects but did not succeed. See HttpComponentsHttpInvokerRequestExecutor's doc. – Chop Dec 19 '14 at 13:55
  • You do not really need an interceptor to force HttpClient to authenticate preemptively. See http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java – ok2c Dec 19 '14 at 14:14
  • True, but the interceptor here seems to be my best way to gain access to the HttpContext and, as a consequence, to my CredentialProvider. Or did I miss something? Plus, you are focusing on the interceptor part, though it is but one aspect of the question. The real question was: how do I configure the client of my RequestExecutor? Once I know how to do this, I am willing to take as much advice as you are willing to give on what I should do when I configure it, but I think we ought to do first things first. – Chop Dec 19 '14 at 14:28
  • Concerning Apache's examples, they are just that: examples, not fit-all-cases solutions. Please keep in mind my question involves overriding HttpComponentsHttpInvokerRequestExecutor. Your answers are absolutely correct in the absolute, but I need to make do with an existing context which is not always compatible. I am not starting from scratch. – Chop Dec 19 '14 at 14:28
  • 1
    The recommended way to go about HttpClient configuration to wire together an instance of HttpClient which is immutable and can be shared and used concurrently by multiple threads and then use HttpContext instances to customize individual request executions. One should never need to remove interceptors or handlers at runtime. Whether or not you decide to go with the recommended approach is entirely up to you. – ok2c Dec 19 '14 at 15:46
  • Thanks, oleg! That supports my idea #2. Now I will try and have a look at how to do it without using an interceptor if that is possible. – Chop Dec 22 '14 at 07:24
  • Hello again, @oleg. Just wondered if you would be OK to give me some more advice: adding interceptor to a client is not deprecated when using he HttpClientBuilder, and is the only way I find to access the context with Spring's API. If I do add them thus, it is my understanding that I match the recommendations. Am I correct? Also, would you be willing to update your answer with the relevant elements from our exchange, so that I could accept it? Thank you for your help! – Chop Dec 22 '14 at 14:24
  • What Spring API are you using? HttpComponentsClientHttpRequestFactory? – ok2c Dec 22 '14 at 15:34
  • I am using HttpComponentsHttpInvokerRequestExecutor (trying to upgrade code which used CommonsHttpInvokerRequestExecutor). – Chop Dec 23 '14 at 07:04
  • 1
    Unfortunately, unlike HttpComponentsClientHttpRequestFactory, HttpComponentsHttpInvokerRequestExecutor does not provide a means of setting a custom context for request execution. You most likely have to subclass the executor and override its #executeHttpPost method or raise an enhancement request with Spring developers. They are currently working on polishing APIs of their HC based components, so they are likely to be receptive to such request. – ok2c Dec 23 '14 at 09:31