/* * This class is a modified version of ChannelFuture in Netty. * * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package edu.washington.escience.myria.util.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import edu.washington.escience.myria.DbException; /** * This class serves as the root of all the handle objects for asynchronous operations. * <p> * An asynchronous operation is an operation which is issued by one thread and then gets executed/served by, typically, * another execution entity. The execution entity here can be a thread. For example in {@link ExecutorService}, a * {@link Callable} or a {@link Runnable} is submitted by a client thread to an executor pool, in which a thread will * execute the code some time later. The execution entity can also be a group of threads, a group of processes, or even * a group of computers. For example in a parallel computing system, a job is submitted by a client and gets executed on * all the machines governed by the computing system. * * <h3>State machine</h3> * <p> * A {@link OperationFuture} maintains a state machine. The state machine has two different groups of states: * <em>uncompleted</em> or <em>completed (or done)</em>. The completed state group includes three predefined states: * <em>succeed</em>, <em>cancelled</em>, and <em>failed</em>. Implementation classes may add more completed states if * necessary. Once an {@link OperationFuture} enters into a completed state, the state will never get changed. * * <p> * When an operation begins, a new {@link OperationFuture} object is created. The new future is uncompleted initially - * it is neither succeeded, failed, nor cancelled because the operation is not finished yet. If the operation is * finished either successfully, with failure, or by cancellation, the future is marked as completed with more specific * information, such as the cause of the failure. Please note that even failure and cancellation belong to the completed * state. * * * <pre> * +---------------------------+ * | Completed successfully | * +---------------------------+ * +----> isDone() = true | * +--------------------------+ | | isSuccess() = true | * | Uncompleted | | +===========================+ * +--------------------------+ | | Completed with failure | * | isDone() = false | | +---------------------------+ * | isSuccess() = false |----+----> isDone() = true | * | isCancelled() = false | | | getCause() = non-null | * | getCause() = null | | +===========================+ * +--------------------------+ | | Completed by cancellation | * | +---------------------------+ * +----> isDone() = true | * | isCancelled() = true | * +---------------------------+ * </pre> * * * Various methods are provided to let you check if the operation has been completed, wait for the completion, and * retrieve the result of the async operation. It also allows you to add {@link OperationFutureListener}s so you can get * notified when the state of the operation is changed. * * <p> * * There are two predefined types of listeners: <b>Completed State Listeners</b> and <b>Progress Listeners</b>. The * completed state listeners will be notified after the future enters any of the completed state. These listeners will * only be executed once. The progress listeners may get notified zero or more times. The semantic of the progress * listeners are defined by operation future implementations. * * <h3>Thread model</h3> * * The operation task submission thread is typically different from the operation execution thread. But they can be the * same. * * <p> * The state of the future object may get modified by one or more threads (for non-completed states). If a thread is * trying to modified an already-in-completed-state future, it must fail. * * If a thread moves the state of the operation into a completed one, all completed state listeners must be notified * once and only once. The order is not defined. The thread executing them should be either the one caused the completed * state change or a dedicated listener notifier thread. * <p> * * The complete state of the future won't get lost. If a listener is added after the future reached a completed state, * the listener should be executed immediately either by the thread adding the listener or by the dedicated listener * notifier thread. * * */ public interface OperationFuture { /** * Returns <tt>true</tt> if this task completed. * * Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method * will return <tt>true</tt>. * * @return <tt>true</tt> if this task completed */ boolean isDone(); /** * @return {@code true} if and only if the operation was completed successfully. */ boolean isSuccess(); /** * Returns the cause of the failed operation if the operation has failed. * * @return the cause of the failure. {@code null} if succeeded or this future is not completed yet. */ Throwable getCause(); /** * @return {@code true} if and only if this future was cancelled by a {@link #cancel()} method. */ boolean isCancelled(); /** * Cancels the operation associated with this future and notifies all listeners if canceled successfully. * * @return {@code true} if and only if the operation has been canceled. {@code false} if the operation can't be * canceled or is already completed. */ boolean cancel(); /** * Adds the specified listener to this future. The specified listener is notified when this future is * {@linkplain #isDone() done}. If this future is already completed, the specified listener is notified immediately. * * @param listener the listener. * @return this {@link OperationFuture} */ OperationFuture addListener(OperationFutureListener listener); /** * A pre-notify listener will get executed right after the operation is completed and before the threads who are * waiting on this future are wakedup. If the future is already completed, the specified listener is notified * immediately. * * Adds the specified listener to this future. If the future is already completed, the specified listener is notified * immediately. * * @param listener the listener. * @return this {@link OperationFuture} * */ OperationFuture addPreListener(OperationFutureListener listener); /** * Removes the specified listener from this future. The specified listener is no longer notified when this future is * {@linkplain #isDone() done}. If the specified listener is not associated with this future, this method does nothing * and returns silently. * * @param listener the listener to be removed. * @return this {@link OperationFuture} */ OperationFuture removeListener(final OperationFutureListener listener); /** * Waits for this future until it is done, and rethrows the cause of the failure if this future failed. If the cause * of the failure is a checked exception, it is wrapped with a new {@link DbException} before being thrown. * * @throws InterruptedException if interrupted. * @throws DbException if any other error occurs. * @return this {@link OperationFuture}. */ OperationFuture sync() throws InterruptedException, DbException; /** * Waits for this future until it is done, and rethrows the cause of the failure if this future failed. If the cause * of the failure is a checked exception, it is wrapped with a new {@link DbException} before being thrown. * * @return this {@link OperationFuture}. * @throws DbException if any error occurs. */ OperationFuture syncUninterruptibly() throws DbException; /** * Waits for this future to be completed. * * @throws InterruptedException if the current thread was interrupted * @return this {@link OperationFuture}. */ OperationFuture await() throws InterruptedException; /** * Waits for this future to be completed without interruption. This method catches an {@link InterruptedException} and * discards it silently. * * @return this {@link OperationFuture}. */ OperationFuture awaitUninterruptibly(); /** * Waits for this future to be completed within the specified time limit. * * @param timeout the time out. * @param unit time unit of timeout * @return {@code true} if and only if the future was completed within the specified time limit * * @throws InterruptedException if the current thread was interrupted */ boolean await(long timeout, TimeUnit unit) throws InterruptedException; /** * Waits for this future to be completed within the specified time limit without interruption. This method catches an * {@link InterruptedException} and discards it silently. * * @param timeout the time out. * @param unit time unit of timeout * @return {@code true} if and only if the future was completed within the specified time limit */ boolean awaitUninterruptibly(long timeout, TimeUnit unit); }