/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-2012, Geomatys
*
* 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;
* version 2.1 of the License.
*
* 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 org.geotoolkit.coverage.sql;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.CancellationException;
import org.geotoolkit.resources.Errors;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.apache.sis.util.NullArgumentException;
import org.apache.sis.util.ArraysExt;
/**
* Implementation of {@link FutureQuery}.
*
* @param <V> Type of object returned by {@link #get()} or {@link #result()}.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.11
*
* @since 3.11
* @module
*/
final class FutureQueryTask<V> extends FutureTask<V> implements FutureQuery<V> {
/**
* The tasks to run after completion, or {@code null} if none.
*/
private Runnable[] afterCompletion;
/**
* Creates a {@code FutureQueryTask} that will, upon running, execute the given {@code Callable}.
*
* @param callable the callable task.
* @throws NullPointerException if callable is null.
*/
public FutureQueryTask(final Callable<V> callable) {
super(callable);
}
/**
* Convenience method which block until the result is available,
* or throw the appropriate exception otherwise.
*/
@Override
public V result() throws CoverageStoreException, CancellationException {
try {
return get();
} catch (InterruptedException e) {
final CancellationException ex = new CancellationException(e.getLocalizedMessage());
ex.initCause(e);
throw ex;
} catch (ExecutionException e) {
final Throwable cause = e.getCause();
if (cause instanceof Error) {
throw (Error) cause;
}
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof CoverageStoreException) {
throw (CoverageStoreException) cause;
}
throw new CoverageStoreException(cause);
}
}
/**
* Invokes the given task upon completion of this {@link FutureQuery}.
*/
@Override
public void invokeAfterCompletion(Runnable task) {
if (task == null) {
throw new NullArgumentException(Errors.format(Errors.Keys.NullArgument_1, "task"));
}
synchronized (this) {
Runnable[] tasks = afterCompletion;
if (tasks == null) {
tasks = new Runnable[] {task};
} else {
tasks = ArraysExt.append(tasks, task);
}
afterCompletion = tasks;
}
if (isDone()) {
done(); // Not a problem if invoked twice.
}
}
/**
* Run all pending tasks declared to {@link #invokeAfterCompletion(Runnable)},
* and clears the list of pending tasks. While this method is usually invoked
* only once, it is not a problem if it is invoked more often (which may occur
* in some race conditions).
*/
@Override
protected void done() {
final Runnable[] tasks;
synchronized (this) {
tasks = afterCompletion;
afterCompletion = null;
}
if (tasks != null) {
for (final Runnable task : tasks) {
task.run();
}
}
}
}