/*
* Copyright 2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.services.sqs.buffered;
import com.amazonaws.AmazonWebServiceRequest;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* QueueBufferFuture class is used to deliver asynchronous results of various
* QueueBuffer operations. QueueBufferFutures are not cancellable
*/
class QueueBufferFuture<Req extends AmazonWebServiceRequest, Res> implements Future<Res> {
private Res result = null;
private Exception e = null;
private boolean done = false;
/**
* callback we should call after the future is done. may be null
*/
private final QueueBufferCallback<Req, Res> callback;
/**
* every future should hold a reference to the buffer that issued it. that
* way, even if all other references to the buffer are lost, it will not be
* garbage collected while at least one future it issued is still
* outstanding.
*/
private QueueBuffer issuingBuffer = null;
public QueueBufferFuture() {
this(null);
}
public QueueBufferFuture(QueueBufferCallback<Req, Res> cb) {
callback = cb;
}
/**
* Report that the task this future represents has succeeded.
*/
public synchronized void setSuccess(Res paramResult) {
if (done)
return; // can't mark done twice
result = paramResult;
done = true;
notifyAll();
// if we have a callback to call, schedule
// it on a different thread. Who knows what this
// thread is doing.
if (callback != null && issuingBuffer != null) {
QueueBuffer.executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
callback.onSuccess(result);
return null;
}
});
}
}
/**
* Report that the task this future represents has failed.
*/
public synchronized void setFailure(Exception paramE) {
if (done)
return; // can't mark done twice
e = paramE;
done = true;
notifyAll();
// if we have a callback to call, schedule
// it on a different thread. Who knows what this
// thread is doing.
if (callback != null && issuingBuffer != null) {
QueueBuffer.executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
callback.onError(e);
return null;
}
});
}
}
@Override
public boolean cancel(boolean arg0) {
// not cancellable
return false;
}
public void setBuffer(QueueBuffer paramBuffer) {
issuingBuffer = paramBuffer;
}
@Override
public Res get() throws InterruptedException, ExecutionException {
while (true) {
try {
return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (TimeoutException te) {
// shouldn't really happen, since we're specifying a very-very
// long wait. but if it does, just loop
// and wait more.
}
}
}
@Override
public synchronized Res get(long timeout, TimeUnit tu)
throws InterruptedException, ExecutionException,
TimeoutException {
long waitStartMs = TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
long timeoutMs = TimeUnit.MILLISECONDS.convert(timeout, tu);
long timeToWaitMs = timeoutMs;
while (!done) {
// if timeToWaitMs is zero, we don't call wait() at all, because
// wait(0) means
// "wait forever", which is the opposite of what we want.
if (timeToWaitMs <= 0) {
throw new TimeoutException("Timed out waiting for results after " + timeout + " "
+ tu);
}
wait(timeToWaitMs);
// compute how long to wait in the next loop
long nowMs = TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
timeToWaitMs = timeoutMs - (nowMs - waitStartMs);
}
// if we got here, we are done. Throw if there's anything to throw,
// otherwise return the result
if (e != null) {
throw new ExecutionException(e);
}
// may be null, e.g. for Void futures
return result;
}
@Override
public boolean isCancelled() {
// not cancellable
return false;
}
@Override
public synchronized boolean isDone() {
return done;
}
}