Merge "Fix callback group implementation to match the documentation."
This commit is contained in:
@@ -76,6 +76,7 @@ public class AccountApi {
|
||||
.delete(group.add(cb));
|
||||
cb = CallbackGroup.emptyCallback();
|
||||
}
|
||||
group.done();
|
||||
}
|
||||
|
||||
/** Retrieve the HTTP password */
|
||||
|
||||
@@ -131,7 +131,7 @@ public class ProjectAccessScreen extends ProjectScreen {
|
||||
}
|
||||
}));
|
||||
Util.PROJECT_SVC.projectAccess(getProjectKey(),
|
||||
cbs.addGwtjsonrpc(new ScreenLoadCallback<ProjectAccess>(this) {
|
||||
cbs.addFinal(new ScreenLoadCallback<ProjectAccess>(this) {
|
||||
@Override
|
||||
public void preDisplay(ProjectAccess access) {
|
||||
displayReadOnly(access);
|
||||
|
||||
@@ -288,7 +288,7 @@ public class ChangeScreen extends Screen
|
||||
// Handled by last callback's onFailure.
|
||||
}
|
||||
}));
|
||||
ChangeApi.detail(event.getValue().getChange().getId().get(), cbs.add(
|
||||
ChangeApi.detail(event.getValue().getChange().getId().get(), cbs.addFinal(
|
||||
new GerritCallback<com.google.gerrit.client.changes.ChangeInfo>() {
|
||||
@Override
|
||||
public void onSuccess(
|
||||
|
||||
@@ -163,7 +163,7 @@ public class PublishCommentScreen extends AccountScreen implements
|
||||
// Handled by ScreenLoadCallback.onFailure().
|
||||
}
|
||||
}));
|
||||
Util.DETAIL_SVC.patchSetPublishDetail(patchSetId, cbs.addGwtjsonrpc(
|
||||
Util.DETAIL_SVC.patchSetPublishDetail(patchSetId, cbs.addFinal(
|
||||
new ScreenLoadCallback<PatchSetPublishDetail>(this) {
|
||||
@Override
|
||||
protected void preDisplay(final PatchSetPublishDetail result) {
|
||||
|
||||
@@ -95,7 +95,7 @@ public class CodeMirrorDemo extends Screen {
|
||||
.wholeFile()
|
||||
.intraline()
|
||||
.ignoreWhitespace(DiffApi.IgnoreWhitespace.NONE)
|
||||
.get(group.add(new GerritCallback<DiffInfo>() {
|
||||
.get(group.addFinal(new GerritCallback<DiffInfo>() {
|
||||
@Override
|
||||
public void onSuccess(final DiffInfo diff) {
|
||||
new ModeInjector()
|
||||
|
||||
@@ -386,7 +386,7 @@ public abstract class PatchScreen extends Screen implements
|
||||
}
|
||||
}));
|
||||
PatchUtil.DETAIL_SVC.patchScript(patchKey, idSideA, idSideB,
|
||||
settingsPanel.getValue(), cb.addGwtjsonrpc(
|
||||
settingsPanel.getValue(), cb.addFinal(
|
||||
new ScreenLoadCallback<PatchScript>(this) {
|
||||
@Override
|
||||
protected void preDisplay(final PatchScript result) {
|
||||
|
||||
@@ -17,15 +17,18 @@ package com.google.gerrit.client.rpc;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class for grouping together callbacks and calling them in order.
|
||||
* <p>
|
||||
* Callbacks are added to the group with {@link #add(AsyncCallback)}, which
|
||||
* returns a wrapped callback suitable for passing to an asynchronous RPC call.
|
||||
* The last callback must be added using {@link #addFinal(AsyncCallback)} or
|
||||
* {@link #done()} must be invoked.
|
||||
*
|
||||
* The enclosing group buffers returned results and ensures that
|
||||
* {@code onSuccess} is called exactly once for each callback in the group, in
|
||||
* the same order that callbacks were added. This allows callers to, for
|
||||
@@ -39,12 +42,15 @@ import java.util.Map;
|
||||
* processing it.
|
||||
*/
|
||||
public class CallbackGroup {
|
||||
private final List<Object> callbacks;
|
||||
private final Map<Object, Object> results;
|
||||
private boolean failed;
|
||||
private final List<CallbackImpl<?>> callbacks;
|
||||
private final Set<CallbackImpl<?>> remaining;
|
||||
private boolean finalAdded;
|
||||
|
||||
public static <T> AsyncCallback<T> emptyCallback() {
|
||||
return new AsyncCallback<T>() {
|
||||
private boolean failed;
|
||||
private Throwable failedThrowable;
|
||||
|
||||
public static <T> Callback<T> emptyCallback() {
|
||||
return new Callback<T>() {
|
||||
@Override
|
||||
public void onSuccess(T result) {
|
||||
}
|
||||
@@ -56,77 +62,99 @@ public class CallbackGroup {
|
||||
}
|
||||
|
||||
public CallbackGroup() {
|
||||
callbacks = new ArrayList<Object>();
|
||||
results = new HashMap<Object, Object>();
|
||||
callbacks = new ArrayList<CallbackImpl<?>>();
|
||||
remaining = new HashSet<CallbackImpl<?>>();
|
||||
}
|
||||
|
||||
public <T> AsyncCallback<T> add(final AsyncCallback<T> cb) {
|
||||
callbacks.add(cb);
|
||||
return new AsyncCallback<T>() {
|
||||
@Override
|
||||
public void onSuccess(T result) {
|
||||
results.put(cb, result);
|
||||
CallbackGroup.this.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
CallbackGroup.this.onFailure(caught);
|
||||
}
|
||||
};
|
||||
public <T> Callback<T> add(final AsyncCallback<T> cb) {
|
||||
checkFinalAdded();
|
||||
return handleAdd(cb);
|
||||
}
|
||||
|
||||
public <T> com.google.gwtjsonrpc.common.AsyncCallback<T> addGwtjsonrpc(
|
||||
final com.google.gwtjsonrpc.common.AsyncCallback<T> cb) {
|
||||
callbacks.add(cb);
|
||||
return new com.google.gwtjsonrpc.common.AsyncCallback<T>() {
|
||||
@Override
|
||||
public void onSuccess(T result) {
|
||||
results.put(cb, result);
|
||||
CallbackGroup.this.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
CallbackGroup.this.onFailure(caught);
|
||||
}
|
||||
};
|
||||
public <T> Callback<T> addFinal(final AsyncCallback<T> cb) {
|
||||
checkFinalAdded();
|
||||
finalAdded = true;
|
||||
return handleAdd(cb);
|
||||
}
|
||||
|
||||
private void onSuccess() {
|
||||
if (results.size() < callbacks.size()) {
|
||||
return;
|
||||
}
|
||||
for (Object o : callbacks) {
|
||||
Object result = results.get(o);
|
||||
if (o instanceof AsyncCallback) {
|
||||
@SuppressWarnings("unchecked")
|
||||
AsyncCallback<Object> cb = (AsyncCallback<Object>) o;
|
||||
cb.onSuccess(result);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
com.google.gwtjsonrpc.common.AsyncCallback<Object> cb =
|
||||
(com.google.gwtjsonrpc.common.AsyncCallback<Object>) o;
|
||||
cb.onSuccess(result);
|
||||
public void done() {
|
||||
finalAdded = true;
|
||||
applyAllSuccess();
|
||||
}
|
||||
|
||||
private void applyAllSuccess() {
|
||||
if (!failed && finalAdded && remaining.isEmpty()) {
|
||||
for (CallbackImpl<?> cb : callbacks) {
|
||||
cb.applySuccess();
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void onFailure(Throwable caught) {
|
||||
private <T> Callback<T> handleAdd(AsyncCallback<T> cb) {
|
||||
if (failed) {
|
||||
return;
|
||||
cb.onFailure(failedThrowable);
|
||||
return emptyCallback();
|
||||
}
|
||||
failed = true;
|
||||
for (Object o : callbacks) {
|
||||
if (o instanceof AsyncCallback) {
|
||||
@SuppressWarnings("unchecked")
|
||||
AsyncCallback<Object> cb = (AsyncCallback<Object>) o;
|
||||
cb.onFailure(caught);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
com.google.gwtjsonrpc.common.AsyncCallback<Object> cb =
|
||||
(com.google.gwtjsonrpc.common.AsyncCallback<Object>) o;
|
||||
cb.onFailure(caught);
|
||||
|
||||
CallbackImpl<T> wrapper = new CallbackImpl<T>(cb);
|
||||
callbacks.add(wrapper);
|
||||
remaining.add(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private void checkFinalAdded() {
|
||||
if (finalAdded) {
|
||||
throw new IllegalStateException("final callback already added");
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback<T>
|
||||
extends AsyncCallback<T>, com.google.gwtjsonrpc.common.AsyncCallback<T> {
|
||||
}
|
||||
|
||||
private class CallbackImpl<T> implements Callback<T> {
|
||||
AsyncCallback<T> delegate;
|
||||
T result;
|
||||
|
||||
CallbackImpl(AsyncCallback<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(T value) {
|
||||
if (failed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = value;
|
||||
remaining.remove(this);
|
||||
CallbackGroup.this.applyAllSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
if (failed) {
|
||||
return;
|
||||
}
|
||||
|
||||
failed = true;
|
||||
failedThrowable = caught;
|
||||
for (CallbackImpl<?> cb : callbacks) {
|
||||
cb.delegate.onFailure(failedThrowable);
|
||||
cb.delegate = null;
|
||||
cb.result = null;
|
||||
}
|
||||
callbacks.clear();
|
||||
remaining.clear();
|
||||
}
|
||||
|
||||
void applySuccess() {
|
||||
AsyncCallback<T> cb = delegate;
|
||||
if (cb != null) {
|
||||
delegate = null;
|
||||
cb.onSuccess(result);
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +41,12 @@ class Loader {
|
||||
} else {
|
||||
CallbackGroup group = new CallbackGroup();
|
||||
injectCss(Lib.I.css());
|
||||
injectScript(
|
||||
Lib.I.js().getSafeUri(), group.add(new AsyncCallback<Void>() {
|
||||
public void onFailure(Throwable caught) {}
|
||||
public void onSuccess(Void result) {}
|
||||
}));
|
||||
injectScript(Addons.I.mark_selection().getSafeUri(), group.add(cb));
|
||||
injectScript(Addons.I.foldcode().getSafeUri(), group.add(cb));
|
||||
injectScript(Lib.I.js().getSafeUri(),
|
||||
group.add(CallbackGroup.<Void>emptyCallback()));
|
||||
injectScript(Addons.I.mark_selection().getSafeUri(),
|
||||
group.add(CallbackGroup.<Void>emptyCallback()));
|
||||
injectScript(Addons.I.foldcode().getSafeUri(),
|
||||
group.addFinal(cb));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user