blob: 74e7771568091530b2515c9edb7bd572709111a0 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed 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 com.android.camera.async;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A Future which can be used to asynchronously return a result.
*/
public class FutureResult<V> implements Future<V> {
/**
* True if "done" or in the process of being marked "done".
*/
private final AtomicBoolean mDone;
/**
* 0 if "done" and the appropriate one of {@link #mValue},
* {@link #mCancelled}, and {@link #mException} has been set.
*/
private final CountDownLatch mDoneCondition;
private V mValue;
private boolean mCancelled;
private Exception mException;
private final Updatable<Future<V>> mDoneUpdatable;
/**
* @param doneUpdatable An updatable to be notified when the future is done.
*/
public FutureResult(Updatable<Future<V>> doneUpdatable) {
mDone = new AtomicBoolean();
mDoneCondition = new CountDownLatch(1);
mValue = null;
mCancelled = false;
mDoneUpdatable = doneUpdatable;
}
public FutureResult() {
this(new Updatable<Future<V>>() {
@Override
public void update(Future<V> vFutureResult) {
}
});
}
/**
* See {@link Future#cancel}. This Future implementation only supports
* cancellation from the producer-side via {@link #setCancelled}.
*/
@Override
public boolean cancel(boolean b) {
return false;
}
/**
* See {@link Future#isCancelled}.
*/
@Override
public boolean isCancelled() {
return isDone() && mCancelled;
}
/**
* See {@link Future#isDone}.
*/
@Override
public boolean isDone() {
return mDoneCondition.getCount() == 0;
}
private V getAfterDone() throws ExecutionException {
if (mCancelled) {
throw new CancellationException();
}
if (mException == null) {
return mValue;
} else {
throw new ExecutionException(mException);
}
}
/**
* See {@link Future#get()}.
*/
@Override
public V get() throws InterruptedException, ExecutionException, CancellationException {
mDoneCondition.await();
return getAfterDone();
}
/**
* See {@link Future#get(long, java.util.concurrent.TimeUnit)}.
*/
@Override
public V get(long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
TimeoutException {
mDoneCondition.await(timeout, timeUnit);
return getAfterDone();
}
/**
* Marks the future as cancelled.
*
* @return True if successfully marked as cancelled, or false if the future
* was already done.
*/
public boolean setCancelled() {
boolean alreadyDone = mDone.getAndSet(true);
if (alreadyDone) {
return false;
}
mCancelled = true;
mDoneCondition.countDown();
mDoneUpdatable.update(this);
return true;
}
/**
* Sets the result of the future.
*
* @param value The result of the future.
* @return True if the value was set, or false if the future was already
* done and the provided value was discarded.
*/
public boolean setValue(V value) {
boolean alreadyDone = mDone.getAndSet(true);
if (alreadyDone) {
return false;
}
mValue = value;
mDoneCondition.countDown();
mDoneUpdatable.update(this);
return true;
}
/**
* Marks the future as having an execution exception.
*
* @param e The exception.
* @return True if the exception was set, or false if the future was already
* done and the provided exception was discarded.
*/
public boolean setException(Exception e) {
boolean alreadyDone = mDone.getAndSet(true);
if (alreadyDone) {
return false;
}
mException = e;
mDoneCondition.countDown();
mDoneUpdatable.update(this);
return true;
}
/**
* @return The value, if one has been set, or null otherwise.
*/
public V tryGet() {
if (isDone()) {
return mValue;
} else {
return null;
}
}
}