I am using deferredResult on Spring MVC, but using this code, the timeout still are sending back the HTTP code 503 to the client.
future.onCompletion(new Runnable() {
#Override
public void run() {
if(future.isSetOrExpired()){
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
});
Any idea what else to try?
I ran into the same issue. My Spring MVC Controller method originally returned DeferredResult<Object>, but then I realised I wanted to control the HTTP status code. I found the answer here:
https://www.jayway.com/2014/09/09/asynchronous-spring-service/
#RequestMapping("/async")
DeferredResult<ResponseEntity<?>> async(#RequestParam("q") String query) {
DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
ListenableFuture<RepoListDto> repositoryListDto = repoListService.search(query);
repositoryListDto.addCallback(
new ListenableFutureCallback<RepoListDto>() {
#Override
public void onSuccess(RepoListDto result) {
ResponseEntity<RepoListDto> responseEntity =
new ResponseEntity<>(result, HttpStatus.OK);
deferredResult.setResult(responseEntity);
}
#Override
public void onFailure(Throwable t) {
log.error("Failed to fetch result from remote service", t);
ResponseEntity<Void> responseEntity =
new ResponseEntity<>(HttpStatus.SERVICE_UNAVAILABLE);
deferredResult.setResult(responseEntity);
}
}
);
return deferredResult;
}
Just use DeferredResult<ResponseEntity> and you can set both the response and the Http response code in the ResponseEntity.
Related
I've been working on a Java application that utilizes the openshift api. Specifically OpenShift deployment configuration
I have tried to set up a watcher, but my response body is never called. I am already able to get a response from the 'non watcher' APIcalls. I am using the groovy httpbuilder library to fulfill my request
def http = new HTTPBuilder(<<URL TO OPENSHIFT>>)
try {
http.get(path: '/oapi/v1/watch/namespaces/myproject/deploymentconfigs', contentType: "application/json") { resp, reader ->
println(resp)
return reader
}
} catch (HttpResponseException e) {
System.out.println(e)
}
Please Advise on a path forward to set up OpenShift watchers in my application.
An error message is never thrown. minishift logs -f are not providing any feedback either.
Also note that I have gotten this to work with the curl command, documented in the api
You can use the OKHttpClient to handle the http websocket upgrade protocol for you. Note legacy versions of minishift require the query parameter "access_token" when trying to make a websocket connection request
OkHttpClient client = new OkHttpClient();
def token = token
Request request = new Request.Builder()
.get()
.url("https://<<IP>>/oapi/v1/watch/namespaces/<<namespace>>/deploymentconfigs?watch=true&access_token=<<token>>")
.addHeader("Accept", "application/json")
.addHeader("Connection", "close")
.addHeader("Sec-WebSocket-Protocol",'base64url.bearer.authorization.k8s.io.' + Base64.getEncoder().encodeToString(token.getBytes()))
.addHeader('Origin', 'https://<<IP>>')
.build()
WebSocketListener websocketListener= new WebSocketListenerImpl()
client.newWebSocket(request, websocketListener)
WebSocketListenerImpl Class
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class WebSocketListenerImpl extends WebSocketListener {
public WebSocketListenerImpl() {
super();
}
#Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
print "WEBSOCKET OPEN"
}
#Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
print "WEBSOCKET RECEIVED"
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
super.onMessage(webSocket, bytes);
print "WEBSOCKET OPEN"
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
super.onClosing(webSocket, code, reason);
print "WEBSOCKET CLOSING"
}
#Override
public void onClosed(WebSocket webSocket, int code, String reason) {
super.onClosed(webSocket, code, reason);
print "WEBSOCKET CLOSED"
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, #javax.annotation.Nullable Response response) {
super.onFailure(webSocket, t, response);
println "WEBSOCKET FAILED"
}
}
I have a situation where I need to return an "accepted" response for every request received and publish the actual response later to a separate endpoint outside the service.
To implement the 'accepted' Response I implemented a filter.
public class AcknowledgementFilter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.abortWith(Response.accepted().build());
// call Resource method in new Thread() . <------ ?
}
}
Implementation of service endpoints:
#Path("/vendor")
public class VendorHandler {
#POST
public void addVendor(VendorRequest addVendorRequest)){
vendor = new Vendor();
Client.publish(vendor); // publish request to an endpoint
return null;
}
How do I call the addVendor of VendorHandler(or any method depends on request) from the acknowledgement filter?
Is there any other way to implement an accepted response for every request then process the request separately?
You can use AsyncResponse,
#GET
#ManagedAsync
#Produces(MediaType.APPLICATION_JSON)
public void getLives(#Suspended final AsyncResponse asyncResponse,
#DefaultValue("0") #QueryParam("newestid") final int newestId,
#QueryParam("oldestid") final Integer oldestId) {
asyncResponse.setTimeoutHandler(asyncResponse1 -> {
logger.info("reached timeout");
asyncResponse1.resume(Response.ok().build());
});
asyncResponse.setTimeout(5, TimeUnit.MINUTES);
try {
List<Life> lives = oldestId == null ?
Lifes.getLastLives(newestId) : Lifes.getOlderLives(oldestId);
if (lives.size() > 0) {
final GenericEntity<List<Life>> entity = new GenericEntity<List<Life>>(lives) {
};
asyncResponse.resume(entity);
} else LifeProvider.suspend(asyncResponse);
} catch (SQLException e) {
logger.error(e, e);
asyncResponse.resume(new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR));
}
}
Check this Link for more details.
Working on a backend with Spring (Java) and Firebase. We are using the Firebase tokens (appended as an authentication header) to identify the user, using the built in UID.
Unfortunately, extracting this UID from the token must be done asynchronously, so I can only get the token from the onSuccess callback.
To serve a response, I must return an object from the below deleteUser method, however I cannot know what the response will be until I get a success/failure callback!
I can imagine a way to do this by waiting on a flag which is set my the callback, or with some messy timing, but I'm wondering if there is a clean way of handling this without introducing race conditions or lots of extra code. Can anyone help?
Request Mapping (handles request, serves response)
#RequestMapping(value = "/users", method = RequestMethod.DELETE)
public #ResponseBody String deleteUser(#RequestHeader("Authentication") String token) {
FirebaseUtil.getUid(token, new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
//RETURN SUCCESSFUL HERE
}
}, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//RETURN FAILURE HERE
}
});
//MUST RETURN SOMETHING HERE?
User userToDelete = userDao.get(uid); //DONT HAVE THE uid HERE
userDao.delete(uid);
clearUserAccounts(userToDelete);
return uid + " was deleted";
}
FirebaseUtil.getUid()
public static void getUid(String token, OnSuccessListener<FirebaseToken> successListener, OnFailureListener failureListener) {
FirebaseAuth.getInstance()
.verifyIdToken(token)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
While there are ways to block the thread until the asynchronous request finishes, there is a simple and more resource-effective solution since Spring 3.2.
You can use DeferredResult<T> as your return type to enable asynchronous processing. This allows the servlet container to reuse the HTTP worker thread right away, while sparing you the headache of forcefully serializing a chain of asynchronous requests.
By filling out the comments, your code would look like this:
#RequestMapping(value = "/users", method = RequestMethod.DELETE)
public DeferredResult<String> deleteUser(#RequestHeader("Authentication") String token) {
final DeferredResult<String> result = new DeferredResult<>();
FirebaseUtil.getUid(token, new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
User userToDelete = userDao.get(uid);
userDao.delete(uid);
clearUserAccounts(userToDelete);
result.setResult(uid + " was deleted");
}
}, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
result.setErrorResult(e);
}
});
return result;
}
I am using gwt with php.
I am trying to get data fom the http://typing.lc/userInfo.php url.
but the following code returns nothing, but response.getText() is 200, however when i ask http://typing.lc/userInfo.php through browser it returns value.
try
{
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "http://typing.lc/userInfo.php");
builder.setHeader("Content-Type", "application/x-www-form-urlencoded");
builder.sendRequest("", new RequestCallback()
{
#Override
public void onError(Request request, Throwable exception)
{
Window.alert("Error");
}
#Override
public void onResponseReceived(Request request, Response response)
{
Window.alert("Success: " + response.getText());
}
});
}
catch (RequestException e)
{
Window.alert("Exception");
}
You are probably running into a SOP (Same Origin Policy) issue.
See here for possible solutions.
I'm using GWT 2.3 and I have json-p requests in my code similar to this:
JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
jsonp.requestObject(jsonUrl, new AsyncCallback<T>() {
public void onFailure(Throwable throwable) { // error }
public void onSuccess(T t) { //do something }
});
some GET-requests return 200, others 302 and so on, and I should be
able to return a different "answer" respect to this value. How can I
know what's the response value returned?
I think you can not access the response code using the JsonpRequestBuilder. But if you use the standard RequestBuilder instead you can get the response code using getStatusCode(). Of course you have to then the parse the response text yourself.
RequestBuilder r = new RequestBuilder(RequestBuilder.GET, jsonUrl);
r.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// error
}
public void onResponseReceived(Request request, Response response) {
if (response.getStatusCode() == 200) {
//do something
} else if (response.getStatusCode() == 302) {
//do something else
}
}
});