/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.capedwarf.common.threads;
import java.util.concurrent.Callable;
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 java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Very simple direct future.
*
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
*/
public class DirectFuture<T> implements Future<T> {
private ReadWriteLock lock = new ReentrantReadWriteLock();
private final Callable<T> callable;
private T result;
private boolean canceled;
private DirectFuture(Callable<T> callable) {
// should not return null
this.callable = callable;
}
public static <C> Future<C> create(Callable<C> callable) {
return new DirectFuture<C>(callable);
}
public boolean cancel(boolean mayInterruptIfRunning) {
lock.writeLock().lock();
try {
if (result == null) {
canceled = true;
return true;
} else {
return false;
}
} finally {
lock.writeLock().unlock();
}
}
public boolean isCancelled() {
lock.readLock().lock();
try {
return canceled;
} finally {
lock.readLock().unlock();
}
}
public boolean isDone() {
lock.readLock().lock();
try {
return (result != null);
} finally {
lock.readLock().unlock();
}
}
public T get() throws InterruptedException, ExecutionException {
lock.writeLock().lock();
try {
return getInternal();
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw RuntimeException.class.cast(e);
} else if (e instanceof ExecutionException) {
throw ExecutionException.class.cast(e);
} else if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
throw InterruptedException.class.cast(e);
} else {
throw new ExecutionException(e);
}
} finally {
lock.writeLock().unlock();
}
}
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
final long now = System.currentTimeMillis();
if (lock.writeLock().tryLock(timeout, unit) == false) {
throw new TimeoutException("Cannot get a lock in " + unit.toMillis(timeout) + "ms!");
}
try {
final T result = getInternal();
if (System.currentTimeMillis() - now > unit.toMicros(timeout))
throw new TimeoutException("get() took too much time!");
return result;
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw RuntimeException.class.cast(e);
} else if (e instanceof TimeoutException) {
throw TimeoutException.class.cast(e);
} else if (e instanceof ExecutionException) {
throw ExecutionException.class.cast(e);
} else if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
throw InterruptedException.class.cast(e);
} else {
throw new ExecutionException(e);
}
} finally {
lock.writeLock().unlock();
}
}
/**
* Should be invoked with a lock.
*/
protected T getInternal() throws Exception {
if (canceled)
throw new CancellationException("Already canceled: " + callable);
if (result == null) {
result = callable.call();
}
return result;
}
}