I am still new to implement web service request using Play!Framework 2.1 WS library. Now, I have problem on understanding the WS library behaviour.
Firstly, I have code like this :
public static Result espnRss() {
try {
// do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").get().map(
new F.Function<WS.Response, Result>() {
#Override
public Result apply(WS.Response response) throws Throwable {
return ok("Success!"); // success request
}
}
)
);
} catch (Exception e) {
// exception occured
return internalServerError("Oops, connect exception occured!");
}
}
When I try to request the espnRss action, I got SUCCESS response.
Then, I want to set WS timeout on the request. So, I changed my previous code like this :
public static Result espnRss() {
try {
// set request timeout for 1000 ms and do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").setTimeout(1000).get().map(
... // same as previous
)
);
} catch (Exception e) {
// exception occured
return internalServerError("Oops, connect exception occured!");
}
}
My internet connection is not fast (Download speed is about 40 KB/s) and I do that on purpose (set request time out for 1 second) to make exception handling code is executed.
But, I get default response from framework, not internalServerError response the code provided.
Execution Exception
[TimeoutException: No response received after 1000]
Can anyone explain me why the exception on WS request cannot be caught using my code above? How is the best way to handle exception using Play!Framework WS library?
To handle exception that occur on asynchronous request such as WS request with Play!Framework 2.1.0, there is method on Promise named recover(F.Function<java.lang.Throwable,A> function).
The method should be called when we want to handle all exception occured while requesting using WS library. So, I solved the problem using code that looked like following:
public static Result espnRss() {
// do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").setTimeout(100).get().map(
new F.Function<WS.Response, Result>() {
#Override
public Result apply(WS.Response response) throws Throwable {
return ok("Success!"); // success request
}
}
).recover( // to handle error occured on redeemed PROMISE
new F.Function<Throwable, Result>() {
#Override
public Result apply(Throwable throwable) throws Throwable {
// option to distinguish exception
if (throwable instanceof TimeoutException) {
return internalServerError("Oops, time out exception occured!");
} else {
return internalServerError("Oops, other exception occured!");
}
}
}
)
);
}
I am not familiar with the Play framework but async must be returning/using some kind of future. The request is actually performed in a separate Thread which Exceptions are obviously not caught by your try..catch handler.
There must be some function/method like onComplete that you can apply to async allowing you to test the result of running the request.
Related
I'm sure there's something wrong with what I'm doing here. Retrofit does not go to failure even if the code that I'm getting is 400.
AuthenticationService authService = retrofit.create(AuthenticationService.class);
Call<ValidateTokenResponseMessage> request = authService.validateToken(token);
request.enqueue(new Callback<ValidateTokenResponseMessage>() {
#Override
public void onResponse(Call<ValidateTokenResponseMessage> call, retrofit2.Response<ValidateTokenResponseMessage> response) {
// When I try to put a breakpoint here I can see that response.code() is 400.
ValidateTokenResponseMessage body = response.body();
if (!body.getValidToken()) {
// do success
}
}
#Override
public void onFailure(Call<ValidateTokenResponseMessage> call, Throwable t) {
// do failure
}
});
Callback.onFailure only gets called for exceptions like missing internet connection or invalid https etc.
Invoked when a network exception occurred talking to the server or when an unexpected exception occurred creating the request or processing the response.
To check for errors you have to use Response.isSuccessful()
Returns true if code() is in the range [200..300).
I am using AsyncInvoker using Jersey 2.0. This works fine for me. However, thread is not ending after completion of the return. Please note that I don't expect any response for the services I call.
public Future<Response> fire(WebTarget webTarget) {
Future<Response> response = null;
try {
response = webTarget.request(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.headers(headers)
.async().get();
}
catch (Exception e) {
e.printStackTrace();
}
return response;
}
As long as you don't do anything with the actual javax.ws.rs.core.Response that is provided to you once the future value resolves, the request response stream is kept open (and the thread associated with it the raw HTTP request as wel I guess). You should either:
Do something with the javax.ws.rs.core.Response object and close it (or it's stream).
Use .get(MyPojo.class) to have the response steam converted into an actual object. This will close the stream for you and resolve a MyPojo instance in the future instead.
You need to close your client object that you created in the calling method. In the calling method you would have something like below -
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(SERVER_URL).path(API_PATH).path(String.valueOf(id));
fire(webTarget);
So you need to close your client after calling this method -
client.close()
However, the recommended way of closing client is after receiving response. Something like below -
public void fire(WebTarget webTarget) {
try {
webTarget.request(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.headers(headers)
.async().get(new InvocationCallback<Response>() {
#Override
public void completed(Response response) {
// Do whatever your wish with response
client.close();
}
#Override
public void failed(Throwable throwable) {
throwable.printStackTrace();
client.close();
}
});
}
catch (Exception e) {
e.printStackTrace();
}
}
I am using jersey 1.8
to call an external service.
Here is my code.
try{
ClientResponse response = webResource.header(HttpHeaders.AUTHORIZATION, encodedHashString).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).post(ClientResponse.class, formData);
}catch(ClientHandlerException che){
//handelling code here
{
when read timeout exception occurs it gives ClientHandlerException and underlying exception is SocketTimeoutException. But question here is I can not just say that since its ClientHandlerException it is a timeout exception because this exception can happen for other client related errors.
what can be the exact code to handle it, I need to do some handeling if its a read timeout exception.
Try something like this:
try {
ClientResponse response = webResource.header(HttpHeaders.AUTHORIZATION, encodedHashString).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).post(ClientResponse.class, formData);
} catch(ClientHandlerException ex) {
handleClientHandlerException(ex);
}
private void handleClientHandlerException(ClientHandlerException ex) throws ClientHandlerException {
if (ex.getCause() instanceof SocketTimeoutException) {
// handelling SocketTimeoutException code here
}
throw ex;
}
In handleClientHandlerException you also can try something like ExceptionUtils#getRootCause from apache commons lang if cause isn't SocketTimeoutException to get the root cause.
You can use the Throwables.getRootCause method from guava!
I want to catch all unexpected Exceptions in a jersey rest service.
Therefore i wrote an ExceptionMapper:
#Provider
public class ExceptionMapper implements javax.ws.rs.ext.ExceptionMapper<Exception> {
private static Logger logger = LogManager.getLogManager().getLogger(ExceptionMapper.class.getName());
#Override
public Response toResponse(Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Internal error").type("text/plain").build();
}
}
The mapper catches really all exceptions. Therefore i can't write:
public MyResult getById(#PathParam("id")) {
if (checkAnyThing) {
return new MyResult();
}
else {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
}
This is catched by the Mapper. Now i have to write:
public Response getById(#PathParam("id") {
if (checkAnyThing) { {
return Response.ok().entity(new MyResult()).build();
}
else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
Is this the correct way to catch all unexpected exceptions and also return errors (error codes) in jersey? Or is there any other (more correct) way?
WebApplicationException has a getResponse from which we can get the Response. So you can check for a WebApplicationException in your mapper. Maybe something like
#Override
public Response toResponse(Throwable error) {
Response response;
if (error instanceof WebApplicationException) {
WebApplicationException webEx = (WebApplicationException)error;
response = webEx.getResponse();
} else {
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Internal error").type("text/plain").build();
}
return response;
}
That way an instance of WebApplicationException thrown will just return the default response. This will actually handle some other exceptions also, not thrown explictly by your application. WebApplicationException has a few other exception under its hierarchy that are thrown by JAX-RS, for which predefined response/status codes are wrapped.
Exception Status code Description
-------------------------------------------------------------------------------
BadRequestException 400 Malformed message
NotAuthorizedException 401 Authentication failure
ForbiddenException 403 Not permitted to access
NotFoundException 404 Couldn’t find resource
NotAllowedException 405 HTTP method not supported
NotAcceptableException 406 Client media type requested
not supported
NotSupportedException 415 Client posted media type
not supported
InternalServerErrorException 500 General server error
ServiceUnavailableException 503 Server is temporarily unavailable
or busy
That being said, we could explicitly throw any of these exceptions in our code, just to give it more semantic value.
Generally speaking though, the example above may be unnecessary, unless you want to alter the response message/status code, as one can from the table above, the hierarchy of exceptions already have some general mapping. And in most cases, unexpected exceptions will already be mapped to InternalServerErrorException
I have a rest service which will throw an exception and I want to know what will be the best way to handle this.
So I have a rest service which can throw a userdefined exception and I am catching that inside the catch block and throwing that exception again ! and using rest framework to catch that. Similarly for non-user defined exceptions. I thought this will be good as I have number of rest services and all userdefinedexception code handling will be at a same place.
I would like to know is this the proper way of handling exception in rest service ?
I am using jersey.
// rest service
#POST
public void doSomething() {
try {
// ... some piece of code that can throw user defined exception as well as runtime exception
} catch(UserDefinedException e) {
throws new UserDefinedException(e);
} catch(Exception e) {
throws new ServiceException(e);
}
// Now I have a #Provider to catch this thrown exception
#Provider
public class UserDefinedExceptionHandler implements
ExceptionMapper {
public Response toResponse(UserDefinedException exception) {
ClientResponse clientResponse = new ClientResponse();
ResponseStatus status = new ResponseStatus();
clientResponse = handleUserDefinedException(exception, status, clientResponse);
return Response.ok(clientResponse).build();
}
// similarly for the ServiceException
Just raising error 500 at the server don't give much details on the error, one way to gracefully handle errors, is to wrap the response data in a structure with status and data, if the status is error, show the correct message.
something like this in json format :
{
"status": "error",
"data": {
"message": "detailed error message"
}
}
Handling exceptions in a REST service is not much different from handling exceptions in any other piece of code.
The only "convention" is to throw back an HTTP 400 if the exception is triggered by the client sending incorrect data and a 500 when your service is failing unexpectedly.