Skip to content

Commit 7b0490a

Browse files
committed
Changed restmodel to use CompletableFuture from java 8
1 parent 646cbc8 commit 7b0490a

File tree

5 files changed

+117
-101
lines changed

5 files changed

+117
-101
lines changed

src/main/java/org/codebrewery/CrudModelInterface.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.ning.http.client.ListenableFuture;
44

55
import java.io.IOException;
6+
import java.util.concurrent.CompletableFuture;
67
import java.util.concurrent.ExecutionException;
78

89
/**
@@ -26,26 +27,26 @@ public interface CrudModelInterface {
2627
*
2728
* The url will be constructed the following way baseurl + identifierValue
2829
*/
29-
void fetch(ActionCompletedInterface actionCompletedInterface) throws ExecutionException, InterruptedException;
30+
CompletableFuture<RESTModel> fetch();
3031

3132
/**
3233
* Destroys the single instance of the model
3334
*
3435
* The url will be constructed the following way baseurl + identifierValue
3536
*/
36-
void destroy(ActionCompletedInterface actionCompletedInterface) throws ExecutionException, InterruptedException;
37+
CompletableFuture<RESTModel> destroy();
3738

3839
/**
3940
* updates the resource
4041
*
4142
* The url will be constructed the following way baseurl + identifierValue
4243
*/
43-
void update(ActionCompletedInterface actionCompletedInterface) throws ExecutionException, InterruptedException, IOException;
44+
CompletableFuture<RESTModel> update() throws IOException;
4445

4546
/**
4647
* Creates a new resource
4748
*
4849
* The url will only consist o fthe base url
4950
*/
50-
void create(ActionCompletedInterface actionCompletedInterface) throws ExecutionException, InterruptedException, IOException;
51+
CompletableFuture<RESTModel> create() throws IOException;
5152
}

src/main/java/org/codebrewery/RESTModel.java

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package org.codebrewery;
22

3-
import com.ning.http.client.AsyncCompletionHandler;
43
import com.ning.http.client.AsyncHttpClient;
4+
import com.ning.http.client.ListenableFuture;
55
import com.ning.http.client.Response;
66
import org.json.simple.parser.ParseException;
77

88
import java.io.IOException;
9+
import java.util.concurrent.CompletableFuture;
10+
import java.util.concurrent.CompletionException;
911
import java.util.concurrent.ExecutionException;
1012

1113

@@ -49,13 +51,13 @@ public abstract class RESTModel implements CrudModelInterface {
4951

5052

5153

52-
protected String generateCollectionUrl() {
54+
String generateCollectionUrl() {
5355

5456
return config.getRequestBaseUrl() + "/" + resourceUrl();
5557

5658
}
5759

58-
protected String generatedInstanceUrl() {
60+
String generatedInstanceUrl() {
5961

6062
return generateCollectionUrl() + "/" + identifierValue();
6163

@@ -72,12 +74,11 @@ public void setConfiguration( RestModelConfiguration config ) {
7274
*
7375
* It will use the JSONConverter, that will use a ObjectMapper to resolve the different attribute names
7476
*
75-
* @param response
7677
* @return
7778
* @throws IOException
7879
* @throws ParseException
7980
*/
80-
protected RESTModel convertJSONToRESTModelObject(String json) throws IOException, ParseException {
81+
RESTModel convertJSONToRESTModelObject(String json) throws IOException, ParseException {
8182

8283
return JSONConverter.unMarshall(json, this.getClass());
8384
}
@@ -91,58 +92,57 @@ protected RESTModel convertJSONToRESTModelObject(String json) throws IOException
9192
* @throws IOException
9293
* @throws ParseException
9394
*/
94-
protected String convertRESTModelToJSON() throws IOException {
95+
String convertRESTModelToJSON() throws IOException {
9596

9697
return JSONConverter.marshall(this);
9798

9899
}
99100

100-
protected AsyncCompletionHandler getAsyncCompletionHandler(ActionCompletedInterface actions) {
101+
CompletableFuture<RESTModel> wrapExecutionInCompletableFuture(ListenableFuture<Response> futureResponse) {
101102

102-
return new AsyncCompletionHandler(){
103+
return CompletableFuture.supplyAsync(() -> {
103104

104-
@Override
105-
public Object onCompleted(Response response) throws Exception {
105+
try {
106+
return convertJSONToRESTModelObject(futureResponse.get().getResponseBody());
107+
} catch (IOException | ParseException | InterruptedException | ExecutionException e4) {
106108

109+
throw new CompletionException(e4);
107110

108-
actions.onDone(convertJSONToRESTModelObject(response.getResponseBody()));
109-
110-
return null;
111111
}
112112

113-
@Override
114-
public void onThrowable(Throwable t) {
115113

116-
actions.onError(t);
114+
});
115+
}
117116

118-
}
119-
};
120117

121-
}
118+
ListenableFuture<Response> execute(AsyncHttpClient.BoundRequestBuilder boundRequestBuilder) {
119+
120+
return boundRequestBuilder.execute();
122121

122+
}
123123

124-
public void fetch(final ActionCompletedInterface actions) throws ExecutionException, InterruptedException {
124+
public CompletableFuture<RESTModel> fetch() {
125125

126-
new AsyncHttpClient().prepareGet(generatedInstanceUrl()).execute(getAsyncCompletionHandler(actions));
126+
return wrapExecutionInCompletableFuture(execute(new AsyncHttpClient().prepareGet(generatedInstanceUrl())));
127127

128128
}
129129

130-
public void destroy(final ActionCompletedInterface actions) throws ExecutionException, InterruptedException {
130+
public CompletableFuture<RESTModel> destroy() {
131131

132-
new AsyncHttpClient().prepareDelete(generatedInstanceUrl()).execute(getAsyncCompletionHandler(actions));
132+
return wrapExecutionInCompletableFuture(execute(new AsyncHttpClient().prepareDelete(generatedInstanceUrl())));
133133

134134
}
135135

136-
public void update(final ActionCompletedInterface actions) throws ExecutionException, InterruptedException, IOException {
136+
public CompletableFuture<RESTModel> update() throws IOException {
137137

138-
new AsyncHttpClient().preparePut(generatedInstanceUrl()).setBody(convertRESTModelToJSON()).execute(getAsyncCompletionHandler(actions));
138+
return wrapExecutionInCompletableFuture(execute(new AsyncHttpClient().preparePut(generatedInstanceUrl()).setBody(convertRESTModelToJSON())));
139139

140140
}
141141

142142

143-
public void create(final ActionCompletedInterface actions) throws ExecutionException, InterruptedException, IOException {
143+
public CompletableFuture<RESTModel> create() throws IOException {
144144

145-
new AsyncHttpClient().preparePost(generateCollectionUrl()).setBody(convertRESTModelToJSON()).execute(getAsyncCompletionHandler(actions));
145+
return wrapExecutionInCompletableFuture(execute(new AsyncHttpClient().preparePost(generateCollectionUrl()).setBody(convertRESTModelToJSON())));
146146

147147
}
148148

src/test/java/org/codebrewery/MockRestModel.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
package org.codebrewery;
22

3+
import com.ning.http.client.AsyncHttpClient;
4+
import com.ning.http.client.ListenableFuture;
5+
import com.ning.http.client.Response;
6+
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
37
import org.json.simple.JSONObject;
48

59
import java.io.IOException;
610

711
/**
812
* Created by jepp3 on 2015-09-06.
913
*/
14+
@JsonIgnoreProperties({"boundRequestBuilder"})
1015
public class MockRestModel extends RESTModel {
1116

1217
public final String name;
18+
private AsyncHttpClient.BoundRequestBuilder boundRequestBuilder;
1319

1420
public MockRestModel() {
1521
this.name = "";
1622
}
23+
1724
public MockRestModel(String name) {
1825
this.name = name;
1926
}
@@ -30,5 +37,15 @@ String identifierValue() {
3037

3138
}
3239

40+
@Override
41+
ListenableFuture<Response> execute(AsyncHttpClient.BoundRequestBuilder boundRequestBuilder) {
42+
43+
this.boundRequestBuilder = boundRequestBuilder;
44+
return null;
3345

46+
}
47+
// for testing
48+
public AsyncHttpClient.BoundRequestBuilder getBoundRequestBuilder() {
49+
return boundRequestBuilder;
50+
}
3451
}

src/test/java/org/codebrewery/TestAbstractRestModel.java

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@
22

33
import com.ning.http.client.AsyncCompletionHandler;
44

5+
import com.ning.http.client.AsyncHttpClient;
6+
import com.ning.http.client.Request;
7+
import com.ning.http.client.Response;
8+
import com.ning.http.client.listenable.AbstractListenableFuture;
59
import org.junit.Before;
610
import org.junit.Test;
711

812

913
import java.io.IOException;
14+
import java.util.concurrent.CompletableFuture;
15+
import java.util.concurrent.ExecutionException;
16+
import java.util.concurrent.TimeUnit;
17+
import java.util.concurrent.TimeoutException;
1018

1119
import static org.junit.Assert.*;
1220

@@ -35,7 +43,7 @@ public void testThatGeneratingFullHttpUrlForInstanceCombinesColectionUrlWithIden
3543

3644
String fullHttpUrl = mockModel.generatedInstanceUrl();
3745

38-
assertEquals("http://localhost:8081/api/dogs/identifier",fullHttpUrl);
46+
assertEquals("http://localhost:8081/api/dogs/identifier", fullHttpUrl);
3947

4048
}
4149

@@ -57,70 +65,98 @@ public String getBaseUrl() {
5765

5866

5967
@Test
60-
public void testThatAsyncCompletionHandlerDoesWhatItsSuposedTo() throws Exception {
68+
public void testConvertRESTModelToJSON() throws IOException {
6169

62-
ActionCompletedInterface mockAction = new ActionCompletedInterface() {
70+
String json = mockModel.convertRESTModelToJSON();
6371

64-
@Override
65-
public void onDone(RESTModel model) {
66-
MockRestModel resp = (MockRestModel) model;
67-
assertNotNull(model);
68-
assertEquals(resp.name, "plutoTheTester");
69-
}
72+
assertEquals("{\"name\":\"plutoTheTester\"}",json);
7073

71-
@Override
72-
public void onError(Throwable e) {
74+
}
7375

74-
fail();
75-
}
76-
};
7776

78-
AsyncCompletionHandler handler = mockModel.getAsyncCompletionHandler(mockAction);
77+
@Test
78+
public void testThatWrapExecutionInCompletableFutureMethodReturnsValidFuture() throws Exception {
79+
7980

80-
// invoke the handler directly
81-
handler.onCompleted(new MockResponse());
81+
CompletableFuture<RESTModel> handler = mockModel.wrapExecutionInCompletableFuture(new AbstractListenableFuture<Response>() {
82+
@Override
83+
public void done() {
8284

85+
}
8386

84-
}
87+
@Override
88+
public void abort(Throwable throwable) {
8589

90+
}
8691

87-
@Test
88-
public void testThatAsyncCompletionHandleronERRORDoesWhatItsSuposedTo() throws Exception {
92+
@Override
93+
public void touch() {
8994

90-
ActionCompletedInterface mockAction = new ActionCompletedInterface() {
95+
}
9196

9297
@Override
93-
public void onDone(RESTModel model) {
98+
public boolean cancel(boolean mayInterruptIfRunning) {
99+
return false;
100+
}
94101

95-
fail();
102+
@Override
103+
public boolean isCancelled() {
104+
return false;
96105
}
97106

98107
@Override
99-
public void onError(Throwable e) {
108+
public boolean isDone() {
109+
return false;
110+
}
100111

101-
assertNotNull(e);
112+
@Override
113+
public Response get() throws InterruptedException, ExecutionException {
114+
return new MockResponse();
115+
}
102116

117+
@Override
118+
public Response get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
119+
return null;
103120
}
104-
};
121+
});
105122

106-
AsyncCompletionHandler handler = mockModel.getAsyncCompletionHandler(mockAction);
123+
MockRestModel resp = (MockRestModel) handler.get();
107124

108-
// invoke the handler directly
109-
handler.onThrowable(new Exception());
125+
assertEquals("plutoTheTester", resp.name);
126+
127+
}
128+
129+
130+
@Test
131+
public void testThatFetchReturnsRightUrl() {
132+
CompletableFuture<RESTModel> future = mockModel.fetch();
133+
Request request = mockModel.getBoundRequestBuilder().build();
110134

135+
assertEquals("http://localhost:8081/api/dogs/identifier",request.getUrl());
111136

112137
}
113138

114139

115140
@Test
116-
public void testConvertRESTModelToJSON() throws IOException {
141+
public void testThatPutReturnsRightUrl() throws IOException {
142+
CompletableFuture<RESTModel> future = mockModel.create();
143+
Request request = mockModel.getBoundRequestBuilder().build();
117144

118-
String json = mockModel.convertRESTModelToJSON();
145+
assertEquals("http://localhost:8081/api/dogs",request.getUrl());
119146

120-
assertEquals("{\"name\":\"plutoTheTester\"}",json);
147+
}
148+
149+
@Test
150+
public void testThatPostReturnsRightUrl() {
151+
CompletableFuture<RESTModel> future = mockModel.destroy();
152+
Request request = mockModel.getBoundRequestBuilder().build();
153+
154+
assertEquals("http://localhost:8081/api/dogs/identifier",request.getUrl());
121155

122156
}
123157

124158

125159

160+
161+
126162
}

0 commit comments

Comments
 (0)