A useful GWT RPC pattern I’ve been using

GWT RPC calls can wind up all over your code, doing all sorts of weird things. If you’re not careful about how you code them you can end up with bugs and other problems cropping up. The other part of RPC calls is that some of them are actually recoverable, and may even be retried a few times before giving up.

I developed the following little bit of code recently that may be useful to anyone doing RPC in GWT:

public abstract class RetryAction<T> implements AsyncCallback<T> {
    public abstract void attempt();
    public abstract void oncapture(T value);

    public void onFailure(Throwable error) {
        try {
            throw error;
        } catch(InvocationException invocationException) {
            Window.alert("A fatal error occurred, you should login " +
                "again or contact Technical Support");
        } catch(IncompatibleRemoteServiceException remoteServiceException) {
            Window.alert("A fatal error occurred, you should login " +
                "again or contact Technical Support");
        } catch(SerializationException serializationException) {
            Window.alert("A fatal error occurred, you should login " +
                "again or contact Technical Support");
        } catch(Throwable throwable) {
            String message = throwable.getLocalizedMessage();

            if(message == null) {
                message = throwable.getMessage();
            }

            if(message == null) {
                message = throwable.getClass().getName();
            }

            if(Window.confirm("An error occured:\n" + message + "\n" +
                "You may retry this operation by clicking 'OK'.\n" +
                "However if the error persists, contact Technical Support.")) {

                attempt();
            }
        }
    }

    public void onSuccess(T value) {
        try {
            oncapture(value);
        } catch(RuntimeException error) {
            onFailure(error);
        }
    }
}

The way this structure works is that you implement your RPC call in the “attempt” method, and the callback in the “oncapture” method. If a “non-fatal” error occurred, the user is given the opportunity to “Retry” the operation (resulting in another call to “attempt”). The pattern groups the RPC invocation nicely with it’s response logic. Here’s a little example:

public class GetContactListAction extends RetryAction<Contacts[]> {
    private ContactList contacts;

    public GetContactListAction(ContactList display) {
        contacts = display;
    }

    public void attempt() {
        CONTACT_LIST_SERVICE_ASYNC.getContactList(this);
    }

    public void oncapture(Contact[] data) {
        contacts.populate(data);
    }
}

And then to use this action:

GetContactListAction action = new GetContactListAction(contactList);
action.attempt();