package org.glassfish.grizzly.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.glassfish.grizzly.Cacheable;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.ThreadCache;
public final class UnsafeFutureImpl<R> implements FutureImpl<R> {
private static final ThreadCache.CachedTypeIndex<UnsafeFutureImpl> CACHE_IDX = ThreadCache.obtainIndex(UnsafeFutureImpl.class, 4);
@SuppressWarnings("unchecked")
public static <R> UnsafeFutureImpl<R> create() {
final UnsafeFutureImpl<R> future = ThreadCache.takeFromCache(CACHE_IDX);
if (future != null) {
return future;
}
return new UnsafeFutureImpl<>();
}
protected boolean isDone;
protected boolean isCancelled;
protected Throwable failure;
protected Set<CompletionHandler<R>> completionHandlers;
protected R result;
protected int recycleMark;
private UnsafeFutureImpl() {
}
@Override
public void addCompletionHandler(final CompletionHandler<R> completionHandler) {
if (isDone) {
notifyCompletionHandler(completionHandler);
} else {
if (completionHandlers == null) {
completionHandlers = new HashSet<>(2);
}
completionHandlers.add(completionHandler);
}
}
@Override
public R getResult() {
return result;
}
@Override
public void result(R result) {
this.result = result;
notifyHaveResult();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
isCancelled = true;
notifyHaveResult();
return true;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public boolean isDone() {
return isDone;
}
@Override
public R get() throws InterruptedException, ExecutionException {
if (isDone) {
if (isCancelled) {
throw new CancellationException();
} else if (failure != null) {
throw new ExecutionException(failure);
} else if (result != null) {
return result;
}
}
throw new ExecutionException(new IllegalStateException("Result is not ready"));
}
@Override
public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return get();
}
@Override
public void failure(Throwable failure) {
this.failure = failure;
notifyHaveResult();
}
protected void notifyHaveResult() {
if (recycleMark == 0) {
isDone = true;
notifyCompletionHandlers();
} else {
recycle(recycleMark == 2);
}
}
private void notifyCompletionHandlers() {
if (completionHandlers != null) {
for (CompletionHandler<R> completionHandler : completionHandlers) {
notifyCompletionHandler(completionHandler);
}
completionHandlers = null;
}
}
private void notifyCompletionHandler(final CompletionHandler<R> completionHandler) {
try {
if (isCancelled) {
completionHandler.cancelled();
} else if (failure != null) {
completionHandler.failed(failure);
} else if (result != null) {
completionHandler.completed(result);
}
} catch (Exception ignored) {
}
}
@Override
public void markForRecycle(boolean recycleResult) {
if (isDone) {
recycle(recycleResult);
} else {
recycleMark = 1 + (recycleResult ? 1 : 0);
}
}
protected void reset() {
completionHandlers = null;
result = null;
failure = null;
isCancelled = false;
isDone = false;
recycleMark = 0;
}
@Override
public void recycle(boolean recycleResult) {
if (recycleResult && result != null && result instanceof Cacheable) {
((Cacheable) result).recycle();
}
reset();
ThreadCache.putToCache(CACHE_IDX, this);
}
@Override
public void recycle() {
recycle(false);
}
}