// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.sdk.util;
import java.util.concurrent.atomic.AtomicBoolean;
import org.chromium.sdk.RelayOk;
import org.chromium.sdk.SyncCallback;
/**
* A utility class for handling {@link SyncCallback} in chained asynchronous operations.
* Whatever happens to each step of operation, {@link SyncCallback} must be called once
* in the end. {@link RelaySyncCallback} wraps the {@link SyncCallback} for the whole
* multistep operation. It works in pair with {@link RelaySyncCallback.Guard} class.
*/
public class RelaySyncCallback {
private final SyncCallback syncCallback;
public RelaySyncCallback(SyncCallback syncCallback) {
this.syncCallback = syncCallback;
}
public Guard newGuard() {
return new Guard();
}
public SyncCallback getUserSyncCallback() {
return syncCallback;
}
/**
* Finish relay by calling {@link SyncCallback}.
*/
public RelayOk finish() {
return finish(syncCallback);
}
public static RelayOk finish(SyncCallback syncCallback) {
if (syncCallback != null) {
syncCallback.callbackDone(null);
}
return FINISH_RELAY_OK;
}
/**
* Responsible for calling SyncCallback unless
* operation has been successfully relayed to the next step.
*/
public class Guard {
private final AtomicBoolean discharged = new AtomicBoolean(false);
/**
* This method should be called when operations was successfully relayed. This is typically
* a last statement in operation step, right before relay call.
* Failing to call {@link #discharge} (because of abnormal finishing) would cause guard to
* call {@link SyncCallback} meaning the termination of the operation.
* @param relayed
*/
public void discharge(RelayOk relayed) {
discharged.set(true);
}
/**
* @return guard wrapped as {@link SyncCallback} that that would let the guard to fulfill its
* main contract
*/
public SyncCallback asSyncCallback() {
return innerSyncCallback;
}
public RelaySyncCallback getRelay() {
return RelaySyncCallback.this;
}
private final SyncCallback innerSyncCallback = new SyncCallback() {
@Override
public void callbackDone(RuntimeException e) {
boolean updated = discharged.compareAndSet(false, true);
if (updated) {
if (syncCallback != null) {
syncCallback.callbackDone(e);
}
}
}
};
}
private static final RelayOk FINISH_RELAY_OK = new RelayOk() {};
}