0

When Tomcat session times out, I want to redirect my user to the homepage of my GWT app, so that they can login again. To force this, I'm trying to use the StatusCodeException thrown by GWT when the user tries to perform any operation after their session times out -

SEVERE: com.google.gwt.user.client.rpc.StatusCodeException: 0  

To achieve this, I'm using the following code -

public void onModuleLoad() {
    GWT.UncaughtExceptionHandler uncaughtExceptionHandler = new GWT.UncaughtExceptionHandler() {
        public void onUncaughtException(Throwable e) {
            if (e instanceof StatusCodeException) {
                logger.log(Level.ERROR, "Exception caught!");
                logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
            }
        }
    };
    GWT.setUncaughtExceptionHandler(uncaughtExceptionHandler);
    try {
        // rest of the code in onModule() - I'm expecting any operation to throw StatusCodeException when session times out.
    } catch (RuntimeException ex) {
        uncaughtExceptionHandler.onUncaughtException(ex);
    }
}

This is not working. Instead of getting caught by the code, the StatusCodeException is being displayed on the console. What am I doing wrong here?

The idea is to catch StatusCodeException and use its getStatusCode() method to find out if the HTTP error code is 403. If it is, I want to use Window.Location.assign("https://example.com/redirect"); to redirect them to a login page.

2
  • 1
    Can you share how you are calling the server in onModuleLoad()? If you are using an AsyncCallback, what is the onFailure method doing? If it isn't actually throwing the exception it gets, then your uncaught exception handler won't see it. Unrelated, status code of 0 does not mean that the session has expired (at least not from any well behaved server...), but that a network error happened, and the browser won't tell the client code what actually took place (dns, request timed out, request refused, cors issue, etc). Commented Jan 10, 2018 at 18:29
  • @ColinAlworth I am using AsyncCallback, configured as onFailure(Throwable caught) { logger.error(caught); }. So, all I need to do is add throws StatusCodeException for UncaughtExceptionHandler to pick it up? Commented Jan 10, 2018 at 23:36

1 Answer 1

1
   onFailure(Throwable caught) { 
       logger.error(caught); 
   }

Your AsyncCallback.onFailure is doing exactly what you asked it to do - it is logging the error, but not throwing it. Since it wasn't thrown, the uncaught exception handler doesn't handle it (it can't be not-caught, if it wasn't thrown... if that makes sense).

One option could be that you could populate the method with throw caught, but java won't like this. Instead, the easiest answer to your specific on is simply to pass it to the handler:

   onFailure(Throwable caught) { 
       GWT.getUncaughtExceptionHandler().onUncaughtException(ex);
   }

One other option you have: since no AsyncCallback will ever throw this, putting the StatusCodeException in the UncaughtExceptionHandler seems a bit odd. Instead, consider making your own AsyncCallback base class, something like this:

public abstract class NetworkAsyncCallback<T> implements AsyncCallback<T> {
    @Override
    public void onFailure(Throwable t) {
        if (e instanceof StatusCodeException) {
            logger.log(Level.ERROR, "Exception caught!");
            logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
        }
    }
}

Now, when you make a call, you just have to pass in a new NetworkAsyncCallback<T> and only implement onSuccess. You can skip onFailure if all it was going to do was pass the exceptions to the uncaught handler. Or, if you have some other logic, you can override onFailure, handle the appropriate exceptions, and call super.onFailure(caught) with any other errors so that the superclass handles it.

myServer.getSomeData(param, new NetworkAsyncCallback<Result>() {
    @Override
    public void onSuccess(Result result) {
        //...
    }
    // Skip onFailure, or if you need custom logic, implement it, 
    // and call super only if the exception isn't part of that logic
});
Sign up to request clarification or add additional context in comments.

5 Comments

This worked, thank you! :) As you mentioned earlier, StatusCodeException.getStatusCode() returns 0 instead of an actual HTTP code, if the request failed. Is there any way I can actually make sure that the error was due to a session timeout?
Depends on how you have the server set up - in general, the server probably should be sending back 401 (or maybe 403?) to indicate that the user doesn't have permission to load that resource. If you are using RPC, you could also make a custom exception that your methods declare with throws. The only other thing I can think of (without seeing server code) is that you are using CORS and contacting a remote server, and that the server isn't sending back a valid response for the initial OPTIONS "preflight" call.
You were right with regards to CORS. I'm using Google OpenID Connect for authentication. When the session times out and an operation is performed, the app tries to hit the j_security_check redirect URL, after which StatusCodeException is thrown; hence the error code 0. Once I disabled CORS, I was able to receive StatusCodeException: 400 Bad Request. Would you happen to know a way around this?
Hmm. A Bad Request response suggests that you probably shouldn't be making that kind of request in the first place - are you trying to reuse the old link instead of restarting the auth flow or something? If your own server is redirecting back to google oauth, could you instead make it send back an error to the client, and detect that instead?
Thanks a lot for your help! Unfortunately, I'm using OpenID Connect Authenticator for Tomcat which does authentication at the container level. I'd have to modify the library itself for such a change. What I was able to do though, was use JSNI to send a request to the base URL when StatusCodeException occurs. If a URL redirect was detected, I know that the server is not in session and can redirect my user to the login page. It's crude, but works. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.