From f023339a383cc44b361032b27cfbf51b5583d2bb Mon Sep 17 00:00:00 2001 From: yuhuihuang Date: Sun, 6 Sep 2020 17:50:18 +0800 Subject: [PATCH] feat: CompletaleFutureTask for async execution --- .../hmcl/task/AsyncTaskExecutor.java | 57 ++++++++++++++++++- .../hmcl/task/CompletableFutureTask.java | 12 ++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/CompletableFutureTask.java diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java index 5d960ffcb..d5c695caa 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java @@ -21,6 +21,7 @@ import com.google.gson.JsonParseException; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.function.ExceptionalRunnable; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.CancellationException; @@ -127,9 +128,61 @@ public final class AsyncTaskExecutor extends TaskExecutor { }); } - private CompletableFuture executeTask(Task parentTask, Task task) { + private CompletableFuture executeTask(Task parentTask, Task task) { checkCancellation(); + if (task instanceof CompletableFutureTask) { + return CompletableFuture.completedFuture(null) + .thenComposeAsync(unused -> { + checkCancellation(); + + task.setCancelled(this::isCancelled); + task.setState(Task.TaskState.READY); + if (parentTask != null && task.getStage() == null) + task.setStage(parentTask.getStage()); + + if (task.getSignificance().shouldLog()) + Logging.LOG.log(Level.FINE, "Executing task: " + task.getName()); + + taskListeners.forEach(it -> it.onRunning(task)); + taskListeners.forEach(it -> it.onReady(task)); + + return ((CompletableFutureTask) task).getCompletableFuture(); + }).whenComplete((result, throwable) -> { + Throwable resolved = resolveException(throwable); + task.setResult(result); + task.setState(Task.TaskState.EXECUTED); + if (isCancelled() || resolved instanceof InterruptedException || resolved instanceof CancellationException) { + task.setException(null); + if (task.getSignificance().shouldLog()) { + Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName()); + } + task.onDone().fireEvent(new TaskEvent(this, task, true)); + taskListeners.forEach(it -> it.onFailed(task, resolved)); + } else if (resolved == null) { + if (task.getSignificance().shouldLog()) { + Logging.LOG.log(Level.FINER, "Task finished: " + task.getName()); + } + + task.onDone().fireEvent(new TaskEvent(this, task, false)); + taskListeners.forEach(it -> it.onFinished(task)); + + task.setState(Task.TaskState.SUCCEEDED); + } else if (resolved instanceof Exception) { + Exception e = (Exception) resolved; + task.setException(e); + exception = e; + if (task.getSignificance().shouldLog()) { + Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e); + } + task.onDone().fireEvent(new TaskEvent(this, task, true)); + taskListeners.forEach(it -> it.onFailed(task, e)); + } else { + throw new CompletionException(resolved); // rethrow error + } + }); + } + return CompletableFuture.completedFuture(null) .thenComposeAsync(unused -> { checkCancellation(); @@ -233,7 +286,7 @@ public final class AsyncTaskExecutor extends TaskExecutor { }); } - private static Throwable resolveException(Throwable e) { + private static Throwable resolveException(@Nullable Throwable e) { if (e instanceof ExecutionException || e instanceof CompletionException) return resolveException(e.getCause()); else diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CompletableFutureTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CompletableFutureTask.java new file mode 100644 index 000000000..b3c19031f --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CompletableFutureTask.java @@ -0,0 +1,12 @@ +package org.jackhuang.hmcl.task; + +import java.util.concurrent.CompletableFuture; + +public abstract class CompletableFutureTask extends Task { + + public abstract CompletableFuture getCompletableFuture(); + + @Override + public void execute() throws Exception { + } +}