/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.common.executors; import java.util.concurrent.atomic.AtomicInteger; /** * Abstraction for computation. * * <p> Computation expressed as StatefulRunnable can be cancelled, but only if it has not * started yet. * * <p> For better decoupling of the code computing the result and the code that handles it, 4 * separate methods are provided: getResult, onSuccess, onFailure and onCancellation. * * <p> This runnable can be run only once. Subsequent calls to run method won't have any effect. */ abstract public class StatefulRunnable<T> implements Runnable { protected static final int STATE_CREATED = 0; protected static final int STATE_STARTED = 1; protected static final int STATE_CANCELLED = 2; protected static final int STATE_FINISHED = 3; protected static final int STATE_FAILED = 4; protected final AtomicInteger mState; public StatefulRunnable() { mState = new AtomicInteger(STATE_CREATED); } @Override public final void run() { if (!mState.compareAndSet(STATE_CREATED, STATE_STARTED)) { return; } T result; try { result = getResult(); } catch (Exception e) { mState.set(STATE_FAILED); onFailure(e); return; } mState.set(STATE_FINISHED); try { onSuccess(result); } finally { disposeResult(result); } } public void cancel() { if (mState.compareAndSet(STATE_CREATED, STATE_CANCELLED)) { onCancellation(); } } /** * Called after computing result successfully. * @param result */ protected void onSuccess(T result) {} /** * Called if exception occurred during computation. * @param e */ protected void onFailure(Exception e) {} /** * Called when the runnable is cancelled. */ protected void onCancellation() {} /** * Called after onSuccess callback completes in order to dispose the result. * @param result */ protected void disposeResult(T result) {} abstract protected T getResult() throws Exception; }