/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.concurrent;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Shuyang Zhou
*/
public class DefaultNoticeableFuture<T>
extends FutureTask<T> implements NoticeableFuture<T> {
@SuppressWarnings("unchecked")
public DefaultNoticeableFuture() {
super((Callable<T>)_emptyCallable);
}
public DefaultNoticeableFuture(Callable<T> callable) {
super(callable);
}
public DefaultNoticeableFuture(Runnable runnable, T result) {
super(runnable, result);
}
@Override
public boolean addFutureListener(FutureListener<T> futureListener) {
if (futureListener == null) {
throw new NullPointerException("Future listener is null");
}
futureListener = new OnceFutureListener<>(futureListener);
if (_futureListeners.add(futureListener)) {
if (isDone()) {
futureListener.complete(this);
}
return true;
}
return false;
}
@Override
public boolean removeFutureListener(FutureListener<T> futureListener) {
if (futureListener == null) {
throw new NullPointerException("Future listener is null");
}
return _futureListeners.remove(
new OnceFutureListener<T>(futureListener));
}
@Override
public void set(T t) {
super.set(t);
}
@Override
public void setException(Throwable t) {
super.setException(t);
}
@Override
protected void done() {
for (FutureListener<T> futureListener : _futureListeners) {
futureListener.complete(this);
}
}
private static final Callable<Object> _emptyCallable =
new Callable<Object>() {
@Override
public Object call() {
return null;
}
};
private final Set<FutureListener<T>> _futureListeners =
new CopyOnWriteArraySet<>();
private static class OnceFutureListener<V> implements FutureListener<V> {
public OnceFutureListener(FutureListener<V> futureListener) {
_futureListener = futureListener;
}
@Override
public void complete(Future<V> future) {
if (_ran.compareAndSet(false, true)) {
_futureListener.complete(future);
}
}
@Override
public boolean equals(Object obj) {
OnceFutureListener<V> onceFutureListener =
(OnceFutureListener<V>)obj;
return _futureListener.equals(onceFutureListener._futureListener);
}
@Override
public int hashCode() {
return _futureListener.hashCode();
}
private final FutureListener<V> _futureListener;
private final AtomicBoolean _ran = new AtomicBoolean();
}
}