package org.jabref.gui.util;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import javafx.concurrent.Task;
/**
* This class is essentially a wrapper around {@link Task}.
* We cannot use {@link Task} directly since it runs certain update notifications on the JavaFX thread,
* and so makes testing harder.
* We take the opportunity and implement a fluid interface.
*
* @param <V> type of the return value of the task
*/
public class BackgroundTask<V> {
private final Callable<V> callable;
private Runnable onRunning;
private Consumer<V> onSuccess;
private Consumer<Exception> onException;
private Runnable onFinished;
private BackgroundTask(Callable<V> callable) {
this.callable = callable;
}
public static <V> BackgroundTask<V> wrap(Callable<V> callable) {
return new BackgroundTask<>(callable);
}
private static <T> Consumer<T> chain(Runnable first, Consumer<T> second) {
if (first != null) {
if (second != null) {
return result -> {
first.run();
second.accept(result);
};
} else {
return result -> first.run();
}
} else {
return second;
}
}
/**
* Sets the {@link Runnable} that is invoked after the task is started.
*/
public BackgroundTask<V> onRunning(Runnable onRunning) {
this.onRunning = onRunning;
return this;
}
/**
* Sets the {@link Consumer} that is invoked after the task is successfully finished.
*/
public BackgroundTask<V> onSuccess(Consumer<V> onSuccess) {
this.onSuccess = onSuccess;
return this;
}
V call() throws Exception {
return callable.call();
}
Runnable getOnRunning() {
return onRunning;
}
Consumer<V> getOnSuccess() {
return chain(onFinished, onSuccess);
}
Consumer<Exception> getOnException() {
return chain(onFinished, onException);
}
public BackgroundTask<V> onFailure(Consumer<Exception> onException) {
this.onException = onException;
return this;
}
public void executeWith(TaskExecutor taskExecutor) {
taskExecutor.execute(this);
}
/**
* Sets the {@link Runnable} that is invoked after the task is finished, irrespectively if it was successful or
* failed with an error.
*/
public BackgroundTask<V> onFinished(Runnable onFinished) {
this.onFinished = onFinished;
return this;
}
}