/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.client.util;
import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.teiid.runtime.client.Messages;
/**
* Implements a call back based future that can also have
* completion listeners.
*/
public class ResultsFuture<T> implements Future<T> {
public static final ResultsFuture<Void> NULL_FUTURE = new ResultsFuture<Void>();
static {
NULL_FUTURE.getResultsReceiver().receiveResults(null);
}
private static final Logger logger = Logger.getLogger("org.teiid"); //$NON-NLS-1$
public interface CompletionListener<T> {
void onCompletion(ResultsFuture<T> future);
}
private LinkedList<CompletionListener<T>> listeners = new LinkedList<CompletionListener<T>>();
private T result;
private Throwable exception;
private boolean done;
private ResultsReceiver<T> resultsReceiver = new ResultsReceiver<T> () {
public void exceptionOccurred(Throwable e) {
synchronized (ResultsFuture.this) {
if (done) {
throw new IllegalStateException("Already sent results"); //$NON-NLS-1$
}
exception = e;
done = true;
ResultsFuture.this.notifyAll();
}
done();
}
public void receiveResults(T results) {
synchronized (ResultsFuture.this) {
if (done) {
throw new IllegalStateException("Already sent results"); //$NON-NLS-1$
}
result = results;
done = true;
ResultsFuture.this.notifyAll();
}
done();
}
};
public ResultsFuture() {
}
public ResultsReceiver<T> getResultsReceiver() {
return resultsReceiver;
}
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public synchronized T get() throws InterruptedException, ExecutionException {
while (!this.done) {
this.wait();
}
return convertResult();
}
protected T convertResult() throws ExecutionException {
if (exception != null) {
throw new ExecutionException(exception);
}
return result;
}
public synchronized T get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
long millis = unit.toMillis(timeout);
long start = System.currentTimeMillis();
while (!this.done) {
long waitTill = start + millis - System.currentTimeMillis();
if (waitTill <= 0) {
throw new TimeoutException();
}
this.wait(waitTill);
}
return convertResult();
}
public boolean isCancelled() {
return false;
}
public synchronized boolean isDone() {
return done;
}
private void done() {
synchronized (this.listeners) {
for (CompletionListener<T> completionListener : this.listeners) {
try {
completionListener.onCompletion(this);
} catch (Throwable t) {
logger.log(Level.SEVERE, Messages.gs(Messages.TEIID.TEIID20031), t);
}
}
this.listeners.clear();
}
}
public void addCompletionListener(CompletionListener<T> listener) {
synchronized (this) {
if (done) {
try {
listener.onCompletion(this);
} catch (Throwable t) {
logger.log(Level.SEVERE, Messages.gs(Messages.TEIID.TEIID20031), t);
}
return;
}
synchronized (this.listeners) {
this.listeners.add(listener);
}
}
}
}