I have setup a following mechanism which uses an async setup with the help of CompletableFuture. doGET is blocked while waiting for doPOST operation to complete.
Class level hashmap
private final Map<String, HttpRequestResponse> requests = new HashMap<>();
HttpRequestResponse Wrapper class
public class HttpRequestResponse {
private final HttpServletRequest request;
private final CompletableFuture<HttpServletResponse> responseSupplier;
public HttpRequestResponse(HttpServletRequest request, CompletableFuture<HttpServletResponse> responseSupplier) {
this.request = request;
this.responseSupplier = responseSupplier;
}
public void supplyResponse(HttpServletResponse response) {
this.responseSupplier.complete(response); //<-- this will release the .get()
}
//getters
public CompletableFuture<HttpServletResponse> getSupplier() {
return responseSupplier;
}
}
doGET
public void doGET(Request jettyReq, HttpServletRequest request, HttpServletResponse response) {
// 1. Read request ID for the request
String xRequestId = request.getHeader("X-Request-ID");
// 2. Upon receiving the request, create the instance of wrapper
// and put it into the map, then wait for the result
HttpRequestResponse responseSupplier = new HttpRequestResponse(request, new CompletableFuture<>());
requests.put(xRequestId, responseSupplier); //add supplier to the map (so that doPOST can retrieve it later)
// perform other processing & perform request to 3rd party server
try {
response = responseSupplier.getSupplier().get(); //<- wait until someone completes the future
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
So here .get() method is a blocking call which is waiting till 3rd party API call made to doPOST is processed completely. As soon as doPOST is done writing a response to the request of doGET, doGET can simply return it.
doPOST
public void doPOST(Request jettyReq, HttpServletRequest request, HttpServletResponse response) {
// upon receiving the response from the 3rd party API on writeGetObjectResponse,
// I will need to get the future by its id, remove it from the map and complete it:
String xRequestId = request.getHeader("X-Request-ID");
HttpRequestResponse responseSupplier = requests.remove(xRequestId); // removes the supplier from the map and returns it to you
// Build a complete response
HttpServletResponse getObjectResponse = response;
// set response headers
getObjectResponse.setContentType("application/json");
getObjectResponse.setCharacterEncoding("UTF-8");
// write payload into response body
String payloadRequest = null;
try {
payloadRequest = getBody(request);
} catch (IOException exception) {
exception.printStackTrace();
}
PrintWriter out = null;
try {
out = getObjectResponse.getWriter();
} catch (IOException exception) {
exception.printStackTrace();
}
out.print(payloadRequest);
out.flush();
// complete the future so that getObject() can access it.
responseSupplier.getSupplier().complete(getObjectResponse);
response.setStatus(HttpServletResponse.SC_OK);
}
The response object I am trying to build can have a large amount of data to return. I am in search of a mechanism where I can perform a streaming return of data or response body. How do I solve this issue?
