// 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() {}; }