Java 8 HttpClient 4.5 HttpGet and HttpPost in one function - java

I'm writing function that will be used with HttpGet and HttpPost.
It's something like that:
private void initialize(HttpRequestBase method)
{
if(method == new HttpPost())
{
String body = "body";
HttpEntity entity = new ByteArrayEntity(body.getBytes("UTF-8"));
method.setEntity(entity);
}
Problem is that HttpRequestBase doesn't support .setEntity. How can I write function that support HttpGet and HttpPost without problems like that?

The way to work around this problem is to check the type using instanceof and use a cast. Like this:
private void initialize(HttpRequestBase method)
{
if(method instanceof HttpPost)
{
String body = "body";
HttpEntity entity = new ByteArrayEntity(body.getBytes("UTF-8"));
((HttpPost) method).setEntity(entity);
}
}
But whenever you use a cast, you should consider that there may be a more elegant solution. In this case, I would argue that a more elegant solution would be to use method overloading and have a specific method for HttpPost instances.
private void initialize(HttpPost method)
{
String body = "body";
HttpEntity entity = new ByteArrayEntity(body.getBytes("UTF-8"));
method.setEntity(entity);
}
Of course this would mean you would need a separate method for HttpGet (and any other subclasses of HttpRequestBase you wish to support). Any common code shared between GET and POST should be extracted into smaller methods that are called by both initialize() methods.
private void initialize(HttpGet method)
{
// ...
}
This, of course, you might argue defeats the whole point of trying to create one handler for both GET and POST. And you would be right. But you should then question the entire exercise of trying to create one method that handles both. Perhaps the most elegant design is to treat them separately. After all, that is precisely what the authors of the framework you're using chose to do.

Related

Can HttpRequestBase be used in Dart / Flutter?

I am trying to do this java code in Dart/Flutter. It is a connection HttpRequestBase from a library called implementation "cz.msebera.android:httpclient:4.4.1.2".
Java example: Inside an activity called HttpPut.java there is a call to this library. Here is the specific part that I want to take to Dart.
protected HttpRequestBase getRequestBase(Request request) throws UnsupportedEncodingException {
cz.msebera.android.httpclient.client.methods.HttpPut httpPost = new cz.msebera.android.httpclient.client.methods.HttpPut(
request.getResource()
);
StringEntity entity = new StringEntity(request.getParameters(), "UTF-8");
entity.setContentType(new BasicHeader("Content-Type", "application/json"));
httpPost.setEntity(entity);
return httpPost;
}
The Request class contains the following:
import java.util.Collection;
public interface Request {
String getResource();
String getParameters();
Collection<String> getHeaders();
What I have tried in Dart is to call the library http: ^ 0.12.1 but it is not exactly what I need. Because although I can do, in this case httpPut(...), I cannot perform the following steps such as StringEntity. How would you solve those problems?
While Flutter does allow you to insert platform-specific code in your app, this is probably not what you want in this case. The classes/methods involved will not be the same, but you should be able to achieve what your Android code does with other classes/methods from Dart. Check out the HttpClient class. Your code might be similar to this (though this snippet is missing request.getParameters(), since I'm not sure what that changes):
Future<HttpClientRequest> getRequestBase(Request request) async {
HttpClientRequest httpRequest = await HttpClient().putUrl(Uri.parse(request.getResource()));
httpRequest.headers.contentType = ContentType('aplication', 'json', charset: 'UTF-8');
return httpRequest;
}
Then, when you want to actually send the request in your code and get the response, you can do
HttpClientRequest requestBase = await getRequestBase(request);
HttpClientResponse response = await requestBase.close();

Avoiding unwanted return value in a java lambda

Is there any way to avoid the return null in this code?
#Test
public void testFrontEndPing() throws Exception {
String url = frontEndUrl("ping");
HttpGet httpGet = new HttpGet(url);
httpClient.execute(httpGet, httpResponse -> {
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
return null;
}
);
}
You can write a wrapper method like this:
static void execute(HttpClient client, HttpUriRequest request,
Consumer<HttpResponse> handler) {
client.<Void>execute(request, response -> {
handler.accept(response);
return null;
});
}
And use it like this:
execute(httpClient, httpGet, httpResponse ->
assertEquals(200, httpResponse.getStatusLine().getStatusCode()));
The Functional Interface you're trying to work with mandates that the function return an object. So no matter how you code this functionality, somewhere you'll have to include 'return null;'
I would advise that you analyze what the code is meant to do, and whether, per the design of your code, you really want that method to always return null.

HttpEntityEnclosingRequestBase and HttpOptions

I need to be able to set an entity on an OPTIONS call but looks like HttpClient does not support it. HttpPost and HttpPut extend from HttpEntityEnclosingRequestBase, while HttpOptions does not.
Anyone know the reason for this, or if there is a way around this?
The HTTP specification states
If the OPTIONS request includes an entity-body (as indicated by the
presence of Content-Length or Transfer-Encoding), then the media type
MUST be indicated by a Content-Type field. Although this specification
does not define any use for such a body, future extensions to HTTP
might use the OPTIONS body to make more detailed queries on the
server. A server that does not support such an extension MAY discard
the request body.
The Apache Http Client team probably decided that there was no use case that would warrant a request body in a OPTIONS request.
In case anyone needs this, here is how did this for HttpClient.
#Autowired
HttpClient httpClient;
public HttpResponse execute(String url, String json, String accessToken) {
HttpOptionsWithBody httpOptionsWithBody = new HttpOptionsWithBody(url);
httpOptionsWithBody.setEntity(new StringEntity(json));
return httpClient.execute(httpOptionsWithBody);
}
private static class HttpOptionsWithBody extends HttpEntityEnclosingRequestBase {
public static final String METHOD_NAME = "OPTIONS";
#Override
public String getMethod() {
return METHOD_NAME;
}
public HttpOptionsWithBody(final String uri) {
super();
setURI(URI.create(uri));
}
}
I got the idea on how to do this from HttpDelete with body

Can we create an HttpResponse Object using the "new" keyword in Java?

I'm working on chapter 4 of Martin Kalin's "Web Services Up and running" book.
In the RestfulTeams exercise there is a method to returns a simple HttpResponse for a restful WS, like:
private Source response_to_client(String msg) {
HttpResponse response = new HttpResponse();
response.setResponse(msg);
ByteArrayInputStream stream = encode_to_stream(response);
return new StreamSource(stream);
}
But I didn't find any library in Java where I can get the HttpResponse class (although I don't think we can create this object directly as in the above method).
Any clarifications will be helpful on how to fix this.
I believe you are thinking about the HttpServletResponse. You can't create your own response objects out of it; the server creates instances of it and makes them available to your application.
But the class in the example is called HttpResponse which either is an error or some other class that the book omits to present.
Writing books is hard, so mistakes can slip by. That's why, after the book is printed, the mistakes that are discovered are documented in an errata. You usually find explanations there and there is always the source code for the book available for study.
Download the source code and I think you'll find what you are looking for, mainly this:
package ch04.team;
import java.io.Serializable;
// Serialized for responses on successful POSTs and PUTs
public class HttpResponse implements Serializable {
private String resp;
public void setResponse(String resp) { this.resp = resp; }
public String getResponse() { return this.resp; }
}

How to use HttpAsyncClient with multithreaded operation?

Closely related to this question: How to use HttpClient with multithreaded operation?, I'm wondering if apache HttpAsyncClient is thread safe, or if it, too, requires the use of a MultiThreadedHttpConnectionManager, or a ThreadSafeClientConnManager.
If it does require such a connection manager, does one exist in the async libraries?
I was able to find a PoolingClientAsyncConnectionManager in the async libraries, but I'm not sure if that's what I need.
Alternately, I was thinking of using ThreadLocal to create one HttpAsyncClient object per thread.
Note that unlike the question I referenced earlier, I need state to be independent across sessions, even if multiple sessions hit the same domain. If a cookie is set in session 1, the cookie should not be visible to session 2. For this reason, I've also considered creating a brand new HttpAsyncClient object for every single request, though I get the impression there should be a better way.
Thanks.
You mention "independent across sessions". If this just means cookies then I would think creating your own CookieStore which is cleared when each of your threads goes to use a HttpClient would be enough.
I would use ThreadLocal to create a per-thread client, don't use a shared connection manager, and then clear the cookies aggressively. This answer was useful around cookie clearing:
Android HttpClient persistent cookies
Something like the following code would work. I've overridden the ThreadLocal.get() method to call clear() in case each request is independent. You could also call clear in the execute(...) method.
private static final ThreadLocal<ClientContext> localHttpContext =
new ThreadLocal<ClientContext> () {
#Override
protected ClientContext initialValue() {
return new ClientContext();
}
#Override
public ClientContext get() {
ClientContext clientContext = super.get();
// could do this to clear the context before usage by the thread
clientContext.clear();
return clientContext;
}
};
...
ClientContext clientContext = localHttpContext.get();
// if this wasn't in the get method above
// clientContext.clear();
HttpGet httpGet = new HttpGet("http://www.google.com/");
HttpResponse response = clientContext.execute(httpGet);
...
private static class ClientContext {
final HttpClient httpClient = new DefaultHttpClient();
final CookieStore cookieStore = new BasicCookieStore();
final HttpContext localContext = new BasicHttpContext();
public ClientContext() {
// bind cookie store to the local context
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
}
public HttpResponse execute(HttpUriRequest request) {
// in case you want each execute to be indepedent
// clientContext.clear();
return httpClient.execute(request, httpContext);
}
public void clear() {
cookieStore.clear();
}
}
After load testing both with and without the PoolingClientAsyncConnectionManager, we discovered that we got inconsistent results when we did not use the PoolingClientAsyncConnectionManager.
Amongst other things, we tracked the number of Http calls we were making, and the number of Http calls that were completed (either through the cancelled(...), completed(...), or failed(...) functions of the associated FutureCallback). Without the PoolingClientAsyncConnectionManager, and under heavy load, the two figures sometimes did not match up, leading us to believe that somewhere, some connections were stomping on connection information from other threads (just a guess).
Either way, with the PoolingClientAsyncConnectionManager, the figures always matched, and the load tests were all successful, so we are definitely using it.
The final code we used goes like this:
public class RequestProcessor {
private RequestProcessor instance = new RequestProcessor();
private PoolingClientAsyncConnectionManager pcm = null;
private HttpAsyncClient httpAsyncClient = null;
private RequestProcessor() {
// Initialize the PoolingClientAsyncConnectionManager, and the HttpAsyncClient
}
public void process(...) {
this.httpAsyncClient.execute(httpMethod,
new BasicHttpContext(), // Use a separate HttpContext for each request so information is not shared between requests
new FutureCallback<HttpResponse>() {
#Override
public void cancelled() {
// Do stuff
}
#Override
public void completed(HttpResponse httpResponse) {
// Do stuff
}
#Override
public void failed(Exception e) {
// Do stuff
}
});
}
}

Categories

Resources