package org.tessell.dispatch.client.util; import java.util.ArrayList; import org.tessell.dispatch.client.DefaultDispatchAsync; import org.tessell.dispatch.client.DispatchAsync; import org.tessell.dispatch.client.SuccessCallback; import org.tessell.dispatch.client.events.DispatchActionEvent; import org.tessell.dispatch.client.events.DispatchFailureEvent; import org.tessell.dispatch.client.events.DispatchResultEvent; import org.tessell.dispatch.client.events.DispatchUnhandledFailureEvent; import org.tessell.dispatch.shared.Action; import org.tessell.dispatch.shared.Result; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.web.bindery.event.shared.EventBus; /** * Fires events outstanding dispatch calls so tests can know when to continue. * * {@link DispatchActionEvent} is fired at the start of every command. * {@link DispatchResultEvent} is fired on success. * {@link DispatchFailureEvent} is fired on every failure. * {@link DispatchUnhandledFailureEvent} is fired on failures when a SuccessCallback was used. */ public class OutstandingDispatchAsync implements DispatchAsync { protected final EventBus eventBus; protected final DispatchAsync delegate; protected final ArrayList<Action<?>> outstanding = new ArrayList<Action<?>>(); /** Fires events on {@code eventBus} with a {@link DefaultDispatchAsync}. */ public OutstandingDispatchAsync(EventBus eventBus) { this(eventBus, new DefaultDispatchAsync(null)); } /** Fires events on {@code eventBus} before making calls against the {@link delegate}. */ public OutstandingDispatchAsync(final EventBus eventBus, final DispatchAsync delegate) { this.eventBus = eventBus; this.delegate = delegate; } @Override public <A extends Action<R>, R extends Result> void execute(final A action, final AsyncCallback<R> callback) { execute(action, callback, null); } /** * Executes {@code action} and defers failure handling from the caller. * * @param action * the action * @param success * the success-only callback, {@link DispatchUnhandledFailureEvent} will be fired on failure */ public <A extends Action<R>, R extends Result> void execute(final A action, final SuccessCallback<R> success) { execute(action, success, null); } /** * Executes {@code action}, defers failure handling from the caller, with an in-progress {@code message}. * * @param action * the action * @param success * the success-only callback, {@link DispatchUnhandledFailureEvent} will be fired on failure * @param message * the in-progress message to include in the {@link DispatchActionEvent}/{@link DispatchResultEvent} events */ public <A extends Action<R>, R extends Result> void execute(final A action, final SuccessCallback<R> success, final String message) { execute(action, new AsyncCallback<R>() { public void onSuccess(final R result) { success.onSuccess(result); } public void onFailure(final Throwable caught) { eventBus.fireEvent(new DispatchUnhandledFailureEvent(action, caught, message)); } }, message); } /** * Executes {@code action} with an in-progress {@code message}. * * @param action * the action * @param callback * the callback for both success and failure (no {@link DispatchUnhandledFailureEvent} will be fired) * @param message * the in-progress message to include in the {@link DispatchActionEvent}/{@link DispatchResultEvent} events */ public <A extends Action<R>, R extends Result> void execute(final A action, final AsyncCallback<R> callback, final String message) { outstanding.add(action); eventBus.fireEvent(new DispatchActionEvent(action, message)); delegate.execute(action, new AsyncCallback<R>() { public void onSuccess(final R result) { outstanding.remove(action); eventBus.fireEvent(new DispatchResultEvent(action, result, message)); callback.onSuccess(result); } public void onFailure(final Throwable caught) { outstanding.remove(action); eventBus.fireEvent(new DispatchFailureEvent(action, caught, message)); callback.onFailure(caught); } }); } public void unhandledFailure(Throwable caught) { eventBus.fireEvent(new DispatchUnhandledFailureEvent(null, caught, null)); } /** @return whether there are any action calls that have not returned from the server */ public boolean hasAnyOutstanding() { return !outstanding.isEmpty(); } /** @return whether there are action calls that have not returned from the server for {@code actionType} */ public <A extends Action<R>, R extends Result> boolean hasOutstanding(final Class<A> actionType) { for (final Action<?> action : outstanding) { if (action.getClass().equals(actionType)) { return true; } } return false; } }