Skip to content

Commit d1a67f9

Browse files
committed
Using NIO instead of threads for asyncronous requests - Closes Kong#3
1 parent a03a2e1 commit d1a67f9

6 files changed

Lines changed: 147 additions & 24 deletions

File tree

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>com.mashape.unirest</groupId>
77
<artifactId>unirest-java</artifactId>
8-
<version>1.0.0</version>
8+
<version>1.1.0</version>
99
<name>unirest-java</name>
1010
<properties>
1111
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -44,6 +44,11 @@
4444
<artifactId>httpclient</artifactId>
4545
<version>4.2.3</version>
4646
</dependency>
47+
<dependency>
48+
<groupId>org.apache.httpcomponents</groupId>
49+
<artifactId>httpasyncclient</artifactId>
50+
<version>4.0-beta3</version>
51+
</dependency>
4752
<dependency>
4853
<groupId>org.apache.httpcomponents</groupId>
4954
<artifactId>httpmime</artifactId>

src/main/java/com/mashape/unirest/http/HttpClientHelper.java

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ a copy of this software and associated documentation files (the
2626
package com.mashape.unirest.http;
2727

2828
import java.util.Map;
29+
import java.util.concurrent.ExecutionException;
30+
import java.util.concurrent.Future;
31+
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.TimeoutException;
2933

3034
import org.apache.http.client.HttpClient;
3135
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
3236
import org.apache.http.client.methods.HttpGet;
3337
import org.apache.http.client.methods.HttpPost;
3438
import org.apache.http.client.methods.HttpPut;
3539
import org.apache.http.client.methods.HttpUriRequest;
40+
import org.apache.http.concurrent.FutureCallback;
3641
import org.apache.http.params.CoreConnectionPNames;
3742
import org.apache.http.params.HttpParams;
3843

44+
import com.mashape.unirest.http.async.Callback;
3945
import com.mashape.unirest.http.utils.ClientFactory;
4046
import com.mashape.unirest.request.HttpRequest;
4147

@@ -46,7 +52,74 @@ public class HttpClientHelper {
4652
private static final int CONNECTION_TIMEOUT = 600000;
4753
private static final int SOCKET_TIMEOUT = 600000;
4854

55+
private static <T> FutureCallback<org.apache.http.HttpResponse> prepareCallback(final Class<T> responseClass, final Callback<T> callback) {
56+
if (callback == null) return null;
57+
58+
return new FutureCallback<org.apache.http.HttpResponse>() {
59+
60+
public void cancelled() {
61+
callback.cancelled();
62+
}
63+
64+
public void completed(org.apache.http.HttpResponse arg0) {
65+
callback.completed(new HttpResponse<T>(arg0, responseClass));
66+
}
67+
68+
public void failed(Exception arg0) {
69+
callback.failed(arg0);
70+
}
71+
72+
};
73+
}
74+
75+
public static <T> Future<HttpResponse<T>> requestAsync(HttpRequest request, final Class<T> responseClass, Callback<T> callback) {
76+
HttpUriRequest requestObj = prepareRequest(request);
77+
78+
final Future<org.apache.http.HttpResponse> future = ClientFactory.getAsyncClient().execute(requestObj, prepareCallback(responseClass, callback));
79+
80+
return new Future<HttpResponse<T>>() {
81+
82+
public boolean cancel(boolean mayInterruptIfRunning) {
83+
return future.cancel(mayInterruptIfRunning);
84+
}
85+
86+
public boolean isCancelled() {
87+
return future.isCancelled();
88+
}
89+
90+
public boolean isDone() {
91+
return future.isDone();
92+
}
93+
94+
public HttpResponse<T> get() throws InterruptedException,
95+
ExecutionException {
96+
org.apache.http.HttpResponse httpResponse = future.get();
97+
return new HttpResponse<T>(httpResponse, responseClass);
98+
}
99+
100+
public HttpResponse<T> get(long timeout, TimeUnit unit)
101+
throws InterruptedException, ExecutionException,
102+
TimeoutException {
103+
org.apache.http.HttpResponse httpResponse = future.get(timeout, unit);
104+
return new HttpResponse<T>(httpResponse, responseClass);
105+
}
106+
};
107+
}
108+
49109
public static <T> HttpResponse<T> request(HttpRequest request, Class<T> responseClass) {
110+
HttpUriRequest requestObj = prepareRequest(request);
111+
HttpClient client = ClientFactory.getClient(); // The DefaultHttpClient is thread-safe
112+
org.apache.http.HttpResponse response;
113+
try {
114+
response = client.execute(requestObj);
115+
} catch (Exception e) {
116+
throw new RuntimeException(e);
117+
}
118+
119+
return new HttpResponse<T>(response, responseClass);
120+
}
121+
122+
private static HttpUriRequest prepareRequest(HttpRequest request) {
50123

51124
request.header("user-agent", USER_AGENT);
52125

@@ -82,15 +155,7 @@ public static <T> HttpResponse<T> request(HttpRequest request, Class<T> response
82155
}
83156

84157
setTimeouts(reqObj.getParams());
85-
HttpClient client = ClientFactory.getClient(); // The DefaultHttpClient is thread-safe
86-
org.apache.http.HttpResponse response;
87-
try {
88-
response = client.execute(reqObj);
89-
} catch (Exception e) {
90-
throw new RuntimeException(e);
91-
}
92-
93-
return new HttpResponse<T>(response, responseClass);
158+
return reqObj;
94159
}
95160

96161
private static void setTimeouts(HttpParams params) {

src/main/java/com/mashape/unirest/http/async/Callback.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ public interface Callback<T> {
3131

3232
void completed(HttpResponse<T> response);
3333

34+
void failed(Exception e);
35+
36+
void cancelled();
3437
}

src/main/java/com/mashape/unirest/http/utils/ClientFactory.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
import org.apache.http.client.HttpClient;
44
import org.apache.http.impl.client.DefaultHttpClient;
5+
import org.apache.http.impl.nio.client.AbstractHttpAsyncClient;
6+
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
7+
import org.apache.http.nio.reactor.IOReactorException;
58

69
public class ClientFactory {
710

811
private static HttpClient httpClient;
12+
private static AbstractHttpAsyncClient asyncHttpClient;
913

1014
public static HttpClient getClient() {
1115
if (httpClient == null) {
@@ -14,4 +18,16 @@ public static HttpClient getClient() {
1418
return httpClient;
1519
}
1620

21+
public static AbstractHttpAsyncClient getAsyncClient() {
22+
if (asyncHttpClient == null) {
23+
try {
24+
asyncHttpClient = new DefaultHttpAsyncClient();
25+
asyncHttpClient.start();
26+
} catch (IOReactorException e) {
27+
throw new RuntimeException(e);
28+
}
29+
}
30+
return asyncHttpClient;
31+
}
32+
1733
}

src/main/java/com/mashape/unirest/request/BaseRequest.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ a copy of this software and associated documentation files (the
2626
package com.mashape.unirest.request;
2727

2828
import java.io.InputStream;
29+
import java.util.concurrent.Future;
2930

3031
import com.mashape.unirest.http.HttpClientHelper;
3132
import com.mashape.unirest.http.HttpResponse;
3233
import com.mashape.unirest.http.JsonNode;
3334
import com.mashape.unirest.http.async.Callback;
34-
import com.mashape.unirest.http.async.RequestThread;
3535

3636
public abstract class BaseRequest {
3737

@@ -49,30 +49,36 @@ public HttpResponse<String> asString() {
4949
return HttpClientHelper.request(httpRequest, String.class);
5050
}
5151

52-
public Thread asString(Callback<String> callback) {
53-
Thread thread = new RequestThread<String>(httpRequest, String.class, callback);
54-
thread.start();
55-
return thread;
52+
public Future<HttpResponse<String>> asStringAsync() {
53+
return HttpClientHelper.requestAsync(httpRequest, String.class, null);
54+
}
55+
56+
public Future<HttpResponse<String>> asStringAsync(Callback<String> callback) {
57+
return HttpClientHelper.requestAsync(httpRequest, String.class, callback);
5658
}
5759

5860
public HttpResponse<JsonNode> asJson() {
5961
return HttpClientHelper.request(httpRequest, JsonNode.class);
6062
}
6163

62-
public Thread asJson(Callback<JsonNode> callback) {
63-
Thread thread = new RequestThread<JsonNode>(httpRequest, JsonNode.class, callback);
64-
thread.start();
65-
return thread;
64+
public Future<HttpResponse<JsonNode>> asJsonAsync() {
65+
return HttpClientHelper.requestAsync(httpRequest, JsonNode.class, null);
66+
}
67+
68+
public Future<HttpResponse<JsonNode>> asJsonAsync(Callback<JsonNode> callback) {
69+
return HttpClientHelper.requestAsync(httpRequest, JsonNode.class, callback);
6670
}
6771

6872
public HttpResponse<InputStream> asBinary() {
6973
return HttpClientHelper.request(httpRequest, InputStream.class);
7074
}
7175

72-
public Thread asBinary(Callback<InputStream> callback) {
73-
Thread thread = new RequestThread<InputStream>(httpRequest, InputStream.class, callback);
74-
thread.start();
75-
return thread;
76+
public Future<HttpResponse<InputStream>> asBinaryAsync() {
77+
return HttpClientHelper.requestAsync(httpRequest, InputStream.class, null);
78+
}
79+
80+
public Future<HttpResponse<InputStream>> asBinaryAsync(Callback<InputStream> callback) {
81+
return HttpClientHelper.requestAsync(httpRequest, InputStream.class, callback);
7682
}
7783

7884
}

src/test/java/com/mashape/unirest/test/http/UnirestTest.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ a copy of this software and associated documentation files (the
3030
import static org.junit.Assert.assertNotNull;
3131
import static org.junit.Assert.assertTrue;
3232

33+
import java.util.concurrent.ExecutionException;
34+
import java.util.concurrent.Future;
35+
36+
import org.json.JSONException;
3337
import org.junit.Test;
3438

3539
import com.mashape.unirest.http.HttpResponse;
@@ -39,7 +43,7 @@ a copy of this software and associated documentation files (the
3943
public class UnirestTest {
4044

4145
@Test
42-
public void testRequests() throws Exception {
46+
public void testRequests() throws JSONException {
4347
HttpResponse<JsonNode> jsonResponse = Unirest.post("http://httpbin.org/post")
4448
.header("accept", "application/json")
4549
.field("param1", "value1")
@@ -59,4 +63,28 @@ public void testRequests() throws Exception {
5963
assertNotNull(json.getArray().get(0));
6064
}
6165

66+
67+
@Test
68+
public void testAsync() throws JSONException, InterruptedException, ExecutionException {
69+
Future<HttpResponse<JsonNode>> future = Unirest.post("http://httpbin.org/post")
70+
.header("accept", "application/json")
71+
.field("param1", "value1")
72+
.field("param2","bye")
73+
.asJsonAsync();
74+
75+
assertNotNull(future);
76+
HttpResponse<JsonNode> jsonResponse = future.get();
77+
78+
assertTrue(jsonResponse.getHeaders().size() > 0);
79+
assertTrue(jsonResponse.getBody().toString().length() > 0);
80+
assertFalse(jsonResponse.getRawBody() == null);
81+
assertEquals(200, jsonResponse.getCode());
82+
83+
JsonNode json = jsonResponse.getBody();
84+
assertFalse(json.isArray());
85+
assertNotNull(json.getObject());
86+
assertNotNull(json.getArray());
87+
assertEquals(1, json.getArray().length());
88+
assertNotNull(json.getArray().get(0));
89+
}
6290
}

0 commit comments

Comments
 (0)