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; } }