From 8f2a1030bc0f4064cce33cf8486128ae4213cd6f Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sun, 24 Feb 2019 23:09:17 +0800 Subject: [PATCH] Refactor Task --- .../hmcl/game/HMCLModpackExportTask.java | 2 +- .../hmcl/game/HMCLModpackInstallTask.java | 10 +- .../jackhuang/hmcl/game/LauncherHelper.java | 18 +- .../jackhuang/hmcl/game/ModpackHelper.java | 6 +- .../MultiMCInstallVersionSettingTask.java | 2 +- .../org/jackhuang/hmcl/ui/Controllers.java | 2 +- .../java/org/jackhuang/hmcl/ui/FXUtils.java | 2 +- .../jackhuang/hmcl/ui/LeftPaneController.java | 4 +- .../hmcl/ui/account/AccountLoginPane.java | 2 +- .../hmcl/ui/account/AddAccountPane.java | 2 +- .../account/AddAuthlibInjectorServerPane.java | 2 +- .../hmcl/ui/construct/TaskListPane.java | 12 +- .../ui/download/InstallerWizardProvider.java | 5 +- .../ModpackInstallWizardProvider.java | 4 +- .../hmcl/ui/download/ModpackPage.java | 2 +- .../VanillaInstallWizardProvider.java | 4 +- .../hmcl/ui/export/ExportWizardProvider.java | 10 +- .../hmcl/ui/versions/InstallerListPage.java | 6 +- .../hmcl/ui/versions/ModListPage.java | 8 +- .../hmcl/ui/versions/VersionSettingsPage.java | 4 +- .../hmcl/ui/versions/WorldExportPage.java | 2 +- .../hmcl/ui/versions/WorldListPage.java | 6 +- .../ui/wizard/AbstractWizardDisplayer.java | 4 +- .../TaskExecutorDialogWizardDisplayer.java | 2 +- .../hmcl/ui/wizard/WizardController.java | 2 +- .../hmcl/ui/wizard/WizardDisplayer.java | 2 +- .../jackhuang/hmcl/upgrade/UpdateHandler.java | 2 +- .../download/DefaultDependencyManager.java | 18 +- .../hmcl/download/DefaultGameBuilder.java | 14 +- .../hmcl/download/DependencyManager.java | 8 +- .../jackhuang/hmcl/download/GameBuilder.java | 2 +- .../jackhuang/hmcl/download/MaintainTask.java | 4 +- .../jackhuang/hmcl/download/VersionList.java | 12 +- .../download/forge/ForgeBMCLVersionList.java | 10 +- .../hmcl/download/forge/ForgeInstallTask.java | 16 +- .../download/forge/ForgeNewInstallTask.java | 13 +- .../download/forge/ForgeOldInstallTask.java | 9 +- .../hmcl/download/forge/ForgeVersionList.java | 6 +- .../download/game/GameAssetDownloadTask.java | 10 +- .../game/GameAssetIndexDownloadTask.java | 7 +- .../hmcl/download/game/GameDownloadTask.java | 7 +- .../hmcl/download/game/GameLibrariesTask.java | 6 +- .../hmcl/download/game/GameVersionList.java | 6 +- .../download/game/LibrariesUniqueTask.java | 4 +- .../download/game/LibraryDownloadTask.java | 4 +- .../game/VersionJsonDownloadTask.java | 11 +- .../download/game/VersionJsonSaveTask.java | 4 +- .../liteloader/LiteLoaderBMCLVersionList.java | 7 +- .../liteloader/LiteLoaderInstallTask.java | 11 +- .../liteloader/LiteLoaderVersionList.java | 7 +- .../optifine/OptiFineBMCLVersionList.java | 6 +- .../optifine/OptiFineInstallTask.java | 11 +- .../jackhuang/hmcl/game/GameRepository.java | 4 +- .../hmcl/mod/CurseCompletionTask.java | 12 +- .../jackhuang/hmcl/mod/CurseInstallTask.java | 10 +- .../hmcl/mod/MinecraftInstanceTask.java | 2 +- .../hmcl/mod/ModpackInstallTask.java | 2 +- .../jackhuang/hmcl/mod/ModpackUpdateTask.java | 8 +- .../hmcl/mod/MultiMCModpackInstallTask.java | 10 +- .../org/jackhuang/hmcl/task/CoupleTask.java | 74 --- .../jackhuang/hmcl/task/FileDownloadTask.java | 2 +- .../java/org/jackhuang/hmcl/task/GetTask.java | 23 +- .../org/jackhuang/hmcl/task/ParallelTask.java | 57 -- .../org/jackhuang/hmcl/task/SimpleTask.java | 52 -- .../jackhuang/hmcl/task/SimpleTaskResult.java | 46 -- .../java/org/jackhuang/hmcl/task/Task.java | 570 +++++++++++++++--- .../org/jackhuang/hmcl/task/TaskEvent.java | 6 +- .../org/jackhuang/hmcl/task/TaskExecutor.java | 279 ++++----- .../org/jackhuang/hmcl/task/TaskListener.java | 8 +- .../org/jackhuang/hmcl/task/TaskResult.java | 247 -------- .../util/function/ExceptionalRunnable.java | 6 +- .../org/jackhuang/hmcl/util/TaskTest.java | 18 + 72 files changed, 841 insertions(+), 935 deletions(-) delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/CoupleTask.java delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/ParallelTask.java delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTask.java delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTaskResult.java delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskResult.java create mode 100644 HMCLCore/src/test/java/org/jackhuang/hmcl/util/TaskTest.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java index 3b01f30a0..c12593034 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java @@ -30,7 +30,7 @@ import java.util.List; /** * Export the game to a mod pack file. */ -public class HMCLModpackExportTask extends Task { +public class HMCLModpackExportTask extends Task { private final DefaultGameRepository repository; private final String version; private final List whitelist; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java index b86ceb340..1fcc1e2f5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java @@ -36,13 +36,13 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; -public final class HMCLModpackInstallTask extends Task { +public final class HMCLModpackInstallTask extends Task { private final File zipFile; private final String name; private final HMCLGameRepository repository; private final Modpack modpack; - private final List dependencies = new LinkedList<>(); - private final List dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); public HMCLModpackInstallTask(Profile profile, File zipFile, Modpack modpack, String name) { DependencyManager dependency = profile.getDependency(); @@ -77,12 +77,12 @@ public final class HMCLModpackInstallTask extends Task { } @Override - public List getDependencies() { + public List> getDependencies() { return dependencies; } @Override - public List getDependents() { + public List> getDependents() { return dependents; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 93e5b34e4..4094deb79 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -121,15 +121,15 @@ public final class LauncherHelper { Version version = MaintainTask.maintain(repository.getResolvedVersion(selectedVersion)); Optional gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version)); - TaskExecutor executor = Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.DEPENDENCIES)) - .then(() -> { + TaskExecutor executor = Task.runAsync(Schedulers.javafx(), () -> emitStatus(LoadingState.DEPENDENCIES)) + .thenCompose(() -> { if (setting.isNotCheckGame()) return null; else return dependencyManager.checkGameCompletionAsync(version); }) - .then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.MODS))) - .then(() -> { + .thenRun(Schedulers.javafx(), () -> emitStatus(LoadingState.MODS)) + .thenCompose(() -> { try { ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); if ("Curse".equals(configuration.getType())) @@ -140,8 +140,8 @@ public final class LauncherHelper { return null; } }) - .then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN))) - .thenCompose(() -> Task.ofResult(i18n("account.methods"), () -> { + .thenRun(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN)) + .thenSupply(i18n("account.methods"), () -> { try { return account.logIn(); } catch (CredentialExpiredException e) { @@ -151,7 +151,7 @@ public final class LauncherHelper { LOG.warning("Authentication failed, try playing offline: " + e); return account.playOffline().orElseThrow(() -> e); } - })) + }) .thenApply(Schedulers.javafx(), authInfo -> { emitStatus(LoadingState.LAUNCHING); return authInfo; @@ -199,7 +199,7 @@ public final class LauncherHelper { final AtomicInteger finished = new AtomicInteger(0); @Override - public void onFinished(Task task) { + public void onFinished(Task task) { finished.incrementAndGet(); int runningTasks = executor.getRunningTasks(); Platform.runLater(() -> launchingStepsPane.setProgress(1.0 * finished.get() / runningTasks)); @@ -416,7 +416,7 @@ public final class LauncherHelper { } } - private static class LaunchTask extends TaskResult { + private static class LaunchTask extends Task { private final ExceptionalSupplier supplier; public LaunchTask(ExceptionalSupplier supplier) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java index 3b256d044..33e5bc3f1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java @@ -86,7 +86,7 @@ public final class ModpackHelper { throw new UnsupportedModpackException(); } - public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) { + public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) { profile.getRepository().markVersionAsModpack(name); ExceptionalRunnable success = () -> { @@ -117,11 +117,11 @@ public final class ModpackHelper { else if (modpack.getManifest() instanceof MultiMCInstanceConfiguration) return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, modpack, ((MultiMCInstanceConfiguration) modpack.getManifest()), name) .whenComplete(Schedulers.defaultScheduler(), success, failure) - .then(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)); + .thenCompose(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)); else throw new IllegalStateException("Unrecognized modpack: " + modpack); } - public static Task getUpdateTask(Profile profile, File zipFile, Charset charset, String name, ModpackConfiguration configuration) throws UnsupportedModpackException, MismatchedModpackTypeException { + public static Task getUpdateTask(Profile profile, File zipFile, Charset charset, String name, ModpackConfiguration configuration) throws UnsupportedModpackException, MismatchedModpackTypeException { Modpack modpack = ModpackHelper.readModpackManifest(zipFile.toPath(), charset); switch (configuration.getType()) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java index e4d6bd6fb..31a3bece9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java @@ -26,7 +26,7 @@ import org.jackhuang.hmcl.task.Task; import java.util.Objects; -public final class MultiMCInstallVersionSettingTask extends Task { +public final class MultiMCInstallVersionSettingTask extends Task { private final Profile profile; private final MultiMCInstanceConfiguration manifest; private final String version; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index 66e462d51..572cc110e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -205,7 +205,7 @@ public final class Controllers { dialog(i18n("launcher.cache_directory.invalid")); } - Task.of(JavaVersion::initialize).start(); + Task.runAsync(JavaVersion::initialize).start(); scene = new Scene(decorator.getDecorator(), 800, 519); scene.getStylesheets().setAll(config().getTheme().getStylesheets()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index f555d7f83..7cb490cd4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -373,7 +373,7 @@ public final class FXUtils { */ @SuppressWarnings("unchecked") @Deprecated - public static void bindEnum(JFXComboBox comboBox, Property property) { + public static void bindEnum(JFXComboBox comboBox, Property> property) { unbindEnum(comboBox); ChangeListener listener = (a, b, newValue) -> ((Property) property).setValue(property.getValue().getClass().getEnumConstants()[newValue.intValue()]); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java index ad0160dee..790c65549 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java @@ -118,12 +118,12 @@ public final class LeftPaneController extends AdvancedListBox { if (repository.getVersionCount() == 0) { File modpackFile = new File("modpack.zip").getAbsoluteFile(); if (modpackFile.exists()) { - Task.ofResult(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath())) + Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath())) .thenApply(encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding)) .thenAccept(modpack -> { AtomicReference region = new AtomicReference<>(); TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack) - .with(Task.of(Schedulers.javafx(), this::checkAccount)).executor(); + .withRun(Schedulers.javafx(), this::checkAccount).executor(); region.set(Controllers.taskDialog(executor, i18n("modpack.installing"))); executor.start(); }).start(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountLoginPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountLoginPane.java index 00646b113..ad955fa71 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountLoginPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountLoginPane.java @@ -61,7 +61,7 @@ public class AccountLoginPane extends StackPane { String password = txtPassword.getText(); progressBar.setVisible(true); lblCreationWarning.setText(""); - Task.ofResult(() -> oldAccount.logInWithPassword(password)) + Task.supplyAsync(() -> oldAccount.logInWithPassword(password)) .whenComplete(Schedulers.javafx(), authInfo -> { success.accept(authInfo); fireEvent(new DialogCloseEvent()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java index 579548f80..9a26ad7b5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java @@ -195,7 +195,7 @@ public class AddAccountPane extends StackPane { AccountFactory factory = cboType.getSelectionModel().getSelectedItem(); Object additionalData = getAuthAdditionalData(); - Task.ofResult(() -> factory.create(new Selector(), username, password, additionalData)) + Task.supplyAsync(() -> factory.create(new Selector(), username, password, additionalData)) .whenComplete(Schedulers.javafx(), account -> { int oldIndex = Accounts.getAccounts().indexOf(account); if (oldIndex == -1) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java index dcb2214c5..b37dbd39c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java @@ -104,7 +104,7 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa nextPane.showSpinner(); addServerPane.setDisable(true); - Task.of(() -> { + Task.runAsync(() -> { serverBeingAdded = AuthlibInjectorServer.locateServer(url); }).whenComplete(Schedulers.javafx(), (isDependentSucceeded, exception) -> { addServerPane.setDisable(false); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java index 9db91119f..9c7996250 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java @@ -42,7 +42,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class TaskListPane extends StackPane { private final AdvancedListBox listBox = new AdvancedListBox(); - private final Map nodes = new HashMap<>(); + private final Map, ProgressListNode> nodes = new HashMap<>(); private final ReadOnlyIntegerWrapper finishedTasks = new ReadOnlyIntegerWrapper(); private final ReadOnlyIntegerWrapper totTasks = new ReadOnlyIntegerWrapper(); @@ -72,12 +72,12 @@ public final class TaskListPane extends StackPane { } @Override - public void onReady(Task task) { + public void onReady(Task task) { Platform.runLater(() -> totTasks.set(totTasks.getValue() + 1)); } @Override - public void onRunning(Task task) { + public void onRunning(Task task) { if (!task.getSignificance().shouldShow()) return; @@ -113,7 +113,7 @@ public final class TaskListPane extends StackPane { } @Override - public void onFinished(Task task) { + public void onFinished(Task task) { ProgressListNode node = nodes.remove(task); if (node == null) return; @@ -125,7 +125,7 @@ public final class TaskListPane extends StackPane { } @Override - public void onFailed(Task task, Throwable throwable) { + public void onFailed(Task task, Throwable throwable) { ProgressListNode node = nodes.remove(task); if (node == null) return; @@ -142,7 +142,7 @@ public final class TaskListPane extends StackPane { private final Label title = new Label(); private final Label state = new Label(); - public ProgressListNode(Task task) { + public ProgressListNode(Task task) { bar.progressProperty().bind(task.progressProperty()); title.setText(task.getName()); state.textProperty().bind(task.messageProperty()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java index 6f826a1a9..a00ec76a6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java @@ -27,7 +27,6 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.DownloadException; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.wizard.WizardController; @@ -90,7 +89,7 @@ public final class InstallerWizardProvider implements WizardProvider { settings.put("success_message", i18n("install.success")); settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next)); - TaskResult ret = Task.ofResult(() -> version); + Task ret = Task.supplyAsync(() -> version); if (settings.containsKey("forge")) ret = ret.thenCompose(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("forge"))); @@ -101,7 +100,7 @@ public final class InstallerWizardProvider implements WizardProvider { if (settings.containsKey("optifine")) ret = ret.thenCompose(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("optifine"))); - return ret.then(profile.getRepository().refreshVersionsAsync()); + return ret.thenCompose(profile.getRepository().refreshVersionsAsync()); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java index 614055ae7..959b807e9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java @@ -71,7 +71,7 @@ public class ModpackInstallWizardProvider implements WizardProvider { settings.put(PROFILE, profile); } - private Task finishModpackInstallingAsync(Map settings) { + private Task finishModpackInstallingAsync(Map settings) { if (!settings.containsKey(ModpackPage.MODPACK_FILE)) return null; @@ -93,7 +93,7 @@ public class ModpackInstallWizardProvider implements WizardProvider { return null; } else { return ModpackHelper.getInstallTask(profile, selected, name, modpack) - .then(Task.of(Schedulers.javafx(), () -> profile.setSelectedVersion(name))); + .thenRun(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java index 7a762498b..ced4dce60 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java @@ -109,7 +109,7 @@ public final class ModpackPage extends StackPane implements WizardPage { } spinnerPane.showSpinner(); - Task.ofResult(() -> CompressingUtils.findSuitableEncoding(selectedFile.toPath())) + Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile.toPath())) .thenApply(encoding -> manifest = ModpackHelper.readModpackManifest(selectedFile.toPath(), encoding)) .whenComplete(Schedulers.javafx(), manifest -> { spinnerPane.hideSpinner(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java index e64696b2c..4deceef5b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java @@ -43,7 +43,7 @@ public final class VanillaInstallWizardProvider implements WizardProvider { settings.put(PROFILE, profile); } - private Task finishVersionDownloadingAsync(Map settings) { + private Task finishVersionDownloadingAsync(Map settings) { GameBuilder builder = profile.getDependency().gameBuilder(); String name = (String) settings.get("name"); @@ -60,7 +60,7 @@ public final class VanillaInstallWizardProvider implements WizardProvider { builder.version((RemoteVersion) settings.get("optifine")); return builder.buildAsync().whenComplete((a, b) -> profile.getRepository().refreshVersions()) - .then(Task.of(Schedulers.javafx(), () -> profile.setSelectedVersion(name))); + .thenRun(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java index f3fef3b8b..f274d9745 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java @@ -60,8 +60,8 @@ public final class ExportWizardProvider implements WizardProvider { List launcherJar = Launcher.getCurrentJarFiles(); boolean includeLauncher = (Boolean) settings.get(ModpackInfoPage.MODPACK_INCLUDE_LAUNCHER) && launcherJar != null; - return new Task() { - Task dependency = null; + return new Task() { + Task dependency = null; @Override public void execute() throws Exception { @@ -80,7 +80,7 @@ public final class ExportWizardProvider implements WizardProvider { ), tempModpack); if (includeLauncher) { - dependency = dependency.then(Task.of(() -> { + dependency = dependency.thenRun(() -> { try (Zipper zip = new Zipper(modpackFile.toPath())) { Config exported = new Config(); @@ -109,12 +109,12 @@ public final class ExportWizardProvider implements WizardProvider { for (File jar : launcherJar) zip.putFile(jar, jar.getName()); } - })); + }); } } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return Collections.singleton(dependency); } }; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java index 020ff62de..b7db33443 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java @@ -54,9 +54,9 @@ public class InstallerListPage extends ListPage { LinkedList newList = new LinkedList<>(version.getLibraries()); newList.remove(library); new MaintainTask(version.setLibraries(newList)) - .then(maintainedVersion -> new VersionJsonSaveTask(profile.getRepository(), maintainedVersion)) - .with(profile.getRepository().refreshVersionsAsync()) - .with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId))) + .thenCompose(maintainedVersion -> new VersionJsonSaveTask(profile.getRepository(), maintainedVersion)) + .withCompose(profile.getRepository().refreshVersionsAsync()) + .withRun(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId)) .start(); }; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java index 62a4da721..1b9050e0b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java @@ -85,7 +85,7 @@ public final class ModListPage extends Control { public void loadMods(ModManager modManager) { this.modManager = modManager; - Task.ofResult(() -> { + Task.supplyAsync(() -> { synchronized (ModListPage.this) { JFXUtilities.runInFX(() -> loadingProperty().set(true)); modManager.refreshMods(); @@ -111,7 +111,7 @@ public final class ModListPage extends Control { List succeeded = new LinkedList<>(); List failed = new LinkedList<>(); if (res == null) return; - Task.of(() -> { + Task.runAsync(() -> { for (File file : res) { try { modManager.addMod(file); @@ -123,7 +123,7 @@ public final class ModListPage extends Control { // Actually addMod will not throw exceptions because FileChooser has already filtered files. } } - }).with(Task.of(Schedulers.javafx(), () -> { + }).withRun(Schedulers.javafx(), () -> { List prompt = new LinkedList<>(); if (!succeeded.isEmpty()) prompt.add(i18n("mods.add.success", String.join(", ", succeeded))); @@ -131,7 +131,7 @@ public final class ModListPage extends Control { prompt.add(i18n("mods.add.failed", String.join(", ", failed))); Controllers.dialog(String.join("\n", prompt), i18n("mods.add")); loadMods(modManager); - })).start(); + }).start(); } public void setParentTab(JFXTabPane parentTab) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index 17619e040..772579c39 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -118,7 +118,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag FXUtils.smoothScrolling(scroll); - Task.ofResult(JavaVersion::getJavas).thenAccept(Schedulers.javafx(), list -> { + Task.supplyAsync(JavaVersion::getJavas).thenAccept(Schedulers.javafx(), list -> { javaItem.loadChildren(list.stream() .map(javaVersion -> javaItem.createChildren(javaVersion.getVersion() + i18n("settings.game.java_directory.bit", javaVersion.getPlatform().getBit()), javaVersion.getBinary().toString(), javaVersion)) @@ -273,7 +273,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag VersionSetting versionSetting = lastVersionSetting; if (versionSetting == null) return; - Task.ofResult(versionSetting::getJavaVersion) + Task.supplyAsync(versionSetting::getJavaVersion) .thenAccept(Schedulers.javafx(), javaVersion -> javaItem.setSubtitle(Optional.ofNullable(javaVersion) .map(JavaVersion::getBinary).map(Path::toString).orElse("Invalid Java Path"))) .start(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldExportPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldExportPage.java index 480f49e01..70ebd9c44 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldExportPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldExportPage.java @@ -74,6 +74,6 @@ public class WorldExportPage extends WizardSinglePage { @Override protected Object finish() { - return Task.of(i18n("world.export.wizard", worldName.get()), () -> world.export(Paths.get(path.get()), worldName.get())); + return Task.runAsync(i18n("world.export.wizard", worldName.get()), () -> world.export(Paths.get(path.get()), worldName.get())); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java index 53095e6d0..4cbc160ae 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListPage.java @@ -50,7 +50,7 @@ public class WorldListPage extends ListPage { this.savesDir = profile.getRepository().getRunDirectory(id).toPath().resolve("saves"); setLoading(true); - Task.ofResult(() -> World.getWorlds(savesDir).parallel().collect(Collectors.toList())) + Task.supplyAsync(() -> World.getWorlds(savesDir).parallel().collect(Collectors.toList())) .whenComplete(Schedulers.javafx(), (result, isDependentSucceeded, exception) -> { setLoading(false); if (isDependentSucceeded) @@ -72,10 +72,10 @@ public class WorldListPage extends ListPage { private void installWorld(File zipFile) { // Only accept one world file because user is required to confirm the new world name // Or too many input dialogs are popped. - Task.ofResult(() -> new World(zipFile.toPath())) + Task.supplyAsync(() -> new World(zipFile.toPath())) .whenComplete(Schedulers.javafx(), world -> { Controllers.inputDialog(i18n("world.name.enter"), (name, resolve, reject) -> { - Task.of(() -> world.install(savesDir, name)) + Task.runAsync(() -> world.install(savesDir, name)) .whenComplete(Schedulers.javafx(), () -> { itemsProperty().add(new WorldListItem(new World(savesDir.resolve(name)))); resolve.run(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java index badfd68b1..999f9aa6f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java @@ -32,8 +32,8 @@ public interface AbstractWizardDisplayer extends WizardDisplayer { Queue getCancelQueue(); @Override - default void handleTask(Map settings, Task task) { - TaskExecutor executor = task.with(Task.of(Schedulers.javafx(), this::navigateToSuccess)).executor(); + default void handleTask(Map settings, Task task) { + TaskExecutor executor = task.withRun(Schedulers.javafx(), this::navigateToSuccess).executor(); TaskListPane pane = new TaskListPane(); pane.setExecutor(executor); navigateTo(pane, Navigation.NavigationDirection.FINISH); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java index 48fb46f0a..41119e2e8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java @@ -35,7 +35,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplayer { @Override - default void handleTask(Map settings, Task task) { + default void handleTask(Map settings, Task task) { TaskExecutorDialogPane pane = new TaskExecutorDialogPane(it -> { it.fireEvent(new DialogCloseEvent()); onEnd(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java index b3bb62ed6..16caab6c9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java @@ -106,7 +106,7 @@ public class WizardController implements Navigation { public void onFinish() { Object result = provider.finish(settings); if (result instanceof Summary) displayer.navigateTo(((Summary) result).getComponent(), NavigationDirection.NEXT); - else if (result instanceof Task) displayer.handleTask(settings, ((Task) result)); + else if (result instanceof Task) displayer.handleTask(settings, ((Task) result)); else if (result != null) throw new IllegalStateException("Unrecognized wizard result: " + result); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java index 43e9397ca..23731ebe8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java @@ -27,5 +27,5 @@ public interface WizardDisplayer { void onEnd(); void onCancel(); void navigateTo(Node page, Navigation.NavigationDirection nav); - void handleTask(Map settings, Task task); + void handleTask(Map settings, Task task); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java index d2cacc977..1be18e552 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java @@ -99,7 +99,7 @@ public final class UpdateHandler { return; } - Task task = new HMCLDownloadTask(version, downloaded); + Task task = new HMCLDownloadTask(version, downloaded); TaskExecutor executor = task.executor(); Controllers.taskDialog(executor, i18n("message.downloading")); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java index ac656d9fc..6e5536f56 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -26,9 +26,7 @@ import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask; import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion; import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.Version; -import org.jackhuang.hmcl.task.ParallelTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.function.ExceptionalFunction; /** @@ -69,9 +67,9 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } @Override - public Task checkGameCompletionAsync(Version version) { - return new ParallelTask( - Task.ofThen(() -> { + public Task checkGameCompletionAsync(Version version) { + return Task.allOf( + Task.composeAsync(() -> { if (!repository.getVersionJar(version).exists()) return new GameDownloadTask(this, null, version); else @@ -83,12 +81,12 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } @Override - public Task checkLibraryCompletionAsync(Version version) { + public Task checkLibraryCompletionAsync(Version version) { return new GameLibrariesTask(this, version); } @Override - public TaskResult installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) { + public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) { VersionList versionList = getVersionList(libraryId); return versionList.loadAsync(gameVersion, getDownloadProvider()) .thenCompose(() -> installLibraryAsync(version, versionList.getVersion(gameVersion, libraryVersion) @@ -96,8 +94,8 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } @Override - public TaskResult installLibraryAsync(Version oldVersion, RemoteVersion libraryVersion) { - TaskResult task; + public Task installLibraryAsync(Version oldVersion, RemoteVersion libraryVersion) { + Task task; if (libraryVersion instanceof ForgeRemoteVersion) task = new ForgeInstallTask(this, oldVersion, (ForgeRemoteVersion) libraryVersion); else if (libraryVersion instanceof LiteLoaderRemoteVersion) @@ -113,7 +111,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } - public ExceptionalFunction, ?> installLibraryAsync(RemoteVersion libraryVersion) { + public ExceptionalFunction, ?> installLibraryAsync(RemoteVersion libraryVersion) { return version -> installLibraryAsync(version, libraryVersion); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java index 60b8f01d6..c3d9994a6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java @@ -19,9 +19,7 @@ package org.jackhuang.hmcl.download; import org.jackhuang.hmcl.download.game.*; import org.jackhuang.hmcl.game.Version; -import org.jackhuang.hmcl.task.ParallelTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.gson.JsonUtils; @@ -48,16 +46,16 @@ public class DefaultGameBuilder extends GameBuilder { } @Override - public Task buildAsync() { + public Task buildAsync() { return new VersionJsonDownloadTask(gameVersion, dependencyManager).thenCompose(rawJson -> { Version original = JsonUtils.GSON.fromJson(rawJson, Version.class); Version version = original.setId(name).setJar(null); - Task vanillaTask = downloadGameAsync(gameVersion, version).then(new ParallelTask( + Task vanillaTask = downloadGameAsync(gameVersion, version).thenCompose(Task.allOf( new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY), new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries. - ).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version))); // using [with] because download failure here are tolerant. + ).withCompose(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version))); // using [with] because download failure here are tolerant. - TaskResult libraryTask = vanillaTask.thenSupply(() -> version); + Task libraryTask = vanillaTask.thenSupply(() -> version); if (toolVersions.containsKey("forge")) libraryTask = libraryTask.thenCompose(libraryTaskHelper(gameVersion, "forge")); @@ -76,11 +74,11 @@ public class DefaultGameBuilder extends GameBuilder { }); } - private ExceptionalFunction, ?> libraryTaskHelper(String gameVersion, String libraryId) { + private ExceptionalFunction, ?> libraryTaskHelper(String gameVersion, String libraryId) { return version -> dependencyManager.installLibraryAsync(gameVersion, version, libraryId, toolVersions.get(libraryId)); } - protected Task downloadGameAsync(String gameVersion, Version version) { + protected Task downloadGameAsync(String gameVersion, Version version) { return new GameDownloadTask(dependencyManager, gameVersion, version); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java index 8dc95bc54..c627bf265 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java @@ -46,7 +46,7 @@ public interface DependencyManager { * * @return the task to check game completion. */ - Task checkGameCompletionAsync(Version version); + Task checkGameCompletionAsync(Version version); /** * Check if the game is complete. @@ -54,7 +54,7 @@ public interface DependencyManager { * * @return the task to check game completion. */ - Task checkLibraryCompletionAsync(Version version); + Task checkLibraryCompletionAsync(Version version); /** * The builder to build a brand new game then libraries such as Forge, LiteLoader and OptiFine. @@ -71,7 +71,7 @@ public interface DependencyManager { * @param libraryVersion the version of being installed library. * @return the task to install the specific library. */ - Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion); + Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion); /** * Install a library to a version. @@ -81,7 +81,7 @@ public interface DependencyManager { * @param libraryVersion the remote version of being installed library. * @return the task to install the specific library. */ - Task installLibraryAsync(Version version, RemoteVersion libraryVersion); + Task installLibraryAsync(Version version, RemoteVersion libraryVersion); /** * Get registered version list. diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/GameBuilder.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/GameBuilder.java index 040af618f..e25aaaef3 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/GameBuilder.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/GameBuilder.java @@ -72,5 +72,5 @@ public abstract class GameBuilder { /** * @return the task that can build thw whole Minecraft environment */ - public abstract Task buildAsync(); + public abstract Task buildAsync(); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java index c0a58dcbc..fc0e818a6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java @@ -18,9 +18,9 @@ package org.jackhuang.hmcl.download; import org.jackhuang.hmcl.game.*; -import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.task.Task; -public class MaintainTask extends TaskResult { +public class MaintainTask extends Task { private final Version version; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/VersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/VersionList.java index da4cc8780..15703b370 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/VersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/VersionList.java @@ -62,19 +62,19 @@ public abstract class VersionList { * @param downloadProvider DownloadProvider * @return the task to reload the remote version list. */ - public abstract Task refreshAsync(DownloadProvider downloadProvider); + public abstract Task refreshAsync(DownloadProvider downloadProvider); /** * @param gameVersion the remote version depends on * @param downloadProvider DownloadProvider * @return the task to reload the remote version list. */ - public Task refreshAsync(String gameVersion, DownloadProvider downloadProvider) { + public Task refreshAsync(String gameVersion, DownloadProvider downloadProvider) { return refreshAsync(downloadProvider); } - public Task loadAsync(DownloadProvider downloadProvider) { - return Task.ofThen(() -> { + public Task loadAsync(DownloadProvider downloadProvider) { + return Task.composeAsync(() -> { lock.readLock().lock(); boolean loaded; @@ -87,8 +87,8 @@ public abstract class VersionList { }); } - public Task loadAsync(String gameVersion, DownloadProvider downloadProvider) { - return Task.ofThen(() -> { + public Task loadAsync(String gameVersion, DownloadProvider downloadProvider) { + return Task.composeAsync(() -> { lock.readLock().lock(); boolean loaded; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java index b412c09ff..fcb999d3f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java @@ -46,21 +46,21 @@ public final class ForgeBMCLVersionList extends VersionList } @Override - public Task loadAsync(DownloadProvider downloadProvider) { + public Task loadAsync(DownloadProvider downloadProvider) { throw new UnsupportedOperationException("ForgeBMCLVersionList does not support loading the entire Forge remote version list."); } @Override - public Task refreshAsync(DownloadProvider downloadProvider) { + public Task refreshAsync(DownloadProvider downloadProvider) { throw new UnsupportedOperationException("ForgeBMCLVersionList does not support loading the entire Forge remote version list."); } @Override - public Task refreshAsync(String gameVersion, DownloadProvider downloadProvider) { + public Task refreshAsync(String gameVersion, DownloadProvider downloadProvider) { final GetTask task = new GetTask(NetworkUtils.toURL("https://bmclapi2.bangbang93.com/forge/minecraft/" + gameVersion)); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java index c29de94a5..222b207ce 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java @@ -21,7 +21,6 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.versioning.VersionNumber; @@ -34,14 +33,14 @@ import java.util.Collections; * * @author huangyuhui */ -public final class ForgeInstallTask extends TaskResult { +public final class ForgeInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final Version version; private Path installer; private final ForgeRemoteVersion remote; - private Task dependent; - private TaskResult dependency; + private Task dependent; + private Task dependency; public ForgeInstallTask(DefaultDependencyManager dependencyManager, Version version, ForgeRemoteVersion remoteVersion) { this.dependencyManager = dependencyManager; @@ -73,20 +72,15 @@ public final class ForgeInstallTask extends TaskResult { } @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(dependent); } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return Collections.singleton(dependency); } - @Override - public boolean isRelyingOnDependencies() { - return false; - } - @Override public void execute() { if (VersionNumber.VERSION_COMPARATOR.compare("1.13", remote.getGameVersion()) <= 0) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java index fe1250485..bdb0d0f8a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java @@ -21,7 +21,6 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.game.GameLibrariesTask; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.gson.JsonUtils; @@ -49,19 +48,19 @@ import static org.jackhuang.hmcl.util.DigestUtils.digest; import static org.jackhuang.hmcl.util.Hex.encodeHex; import static org.jackhuang.hmcl.util.Logging.LOG; -public class ForgeNewInstallTask extends TaskResult { +public class ForgeNewInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final DefaultGameRepository gameRepository; private final Version version; private final Path installer; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); private ForgeNewInstallProfile profile; private Version forgeVersion; - public ForgeNewInstallTask(DefaultDependencyManager dependencyManager, Version version, Path installer) { + ForgeNewInstallTask(DefaultDependencyManager dependencyManager, Version version, Path installer) { this.dependencyManager = dependencyManager; this.gameRepository = dependencyManager.getGameRepository(); this.version = version; @@ -80,12 +79,12 @@ public class ForgeNewInstallTask extends TaskResult { } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @Override - public List getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java index 1c961c91d..3736eadd1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.download.forge; import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.IOUtils; @@ -31,21 +30,21 @@ import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -public class ForgeOldInstallTask extends TaskResult { +public class ForgeOldInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final Version version; private final Path installer; - private final List dependencies = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); - public ForgeOldInstallTask(DefaultDependencyManager dependencyManager, Version version, Path installer) { + ForgeOldInstallTask(DefaultDependencyManager dependencyManager, Version version, Path installer) { this.dependencyManager = dependencyManager; this.version = version; this.installer = installer; } @Override - public List getDependencies() { + public List> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeVersionList.java index 3f9070d08..fb4c5ae19 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeVersionList.java @@ -45,12 +45,12 @@ public final class ForgeVersionList extends VersionList { } @Override - public Task refreshAsync(DownloadProvider downloadProvider) { + public Task refreshAsync(DownloadProvider downloadProvider) { final GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(FORGE_LIST))); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java index 9c435ce41..378141f0b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java @@ -38,14 +38,14 @@ import java.util.List; * * @author huangyuhui */ -public final class GameAssetDownloadTask extends Task { +public final class GameAssetDownloadTask extends Task { private final AbstractDependencyManager dependencyManager; private final Version version; private final AssetIndexInfo assetIndexInfo; private final File assetIndexFile; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); /** * Constructor. @@ -64,12 +64,12 @@ public final class GameAssetDownloadTask extends Task { } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java index c13ef118c..39d166ead 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java @@ -22,7 +22,6 @@ import org.jackhuang.hmcl.game.AssetIndexInfo; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; @@ -34,11 +33,11 @@ import java.util.List; * * @author huangyuhui */ -public final class GameAssetIndexDownloadTask extends Task { +public final class GameAssetIndexDownloadTask extends Task { private final AbstractDependencyManager dependencyManager; private final Version version; - private final List dependencies = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); /** * Constructor. @@ -53,7 +52,7 @@ public final class GameAssetIndexDownloadTask extends Task { } @Override - public List getDependencies() { + public List> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java index f0d4288f1..47d77fe44 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java @@ -26,6 +26,7 @@ import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -33,11 +34,11 @@ import java.util.List; * * @author huangyuhui */ -public final class GameDownloadTask extends Task { +public final class GameDownloadTask extends Task { private final DefaultDependencyManager dependencyManager; private final String gameVersion; private final Version version; - private final List dependencies = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); public GameDownloadTask(DefaultDependencyManager dependencyManager, String gameVersion, Version version) { this.dependencyManager = dependencyManager; @@ -48,7 +49,7 @@ public final class GameDownloadTask extends Task { } @Override - public List getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java index 35519cec7..49ca6e09f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java @@ -32,12 +32,12 @@ import java.util.List; * * @author huangyuhui */ -public final class GameLibrariesTask extends Task { +public final class GameLibrariesTask extends Task { private final AbstractDependencyManager dependencyManager; private final Version version; private final List libraries; - private final List dependencies = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); /** * Constructor. @@ -64,7 +64,7 @@ public final class GameLibrariesTask extends Task { } @Override - public List getDependencies() { + public List> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java index 855e65c5c..d246baa62 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java @@ -55,11 +55,11 @@ public final class GameVersionList extends VersionList { } @Override - public Task refreshAsync(DownloadProvider downloadProvider) { + public Task refreshAsync(DownloadProvider downloadProvider) { GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.getVersionListURL())); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibrariesUniqueTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibrariesUniqueTask.java index 23d586c1e..0ecece4c0 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibrariesUniqueTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibrariesUniqueTask.java @@ -20,7 +20,7 @@ package org.jackhuang.hmcl.download.game; import org.jackhuang.hmcl.game.CompatibilityRule; import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; -import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.SimpleMultimap; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.versioning.VersionNumber; @@ -31,7 +31,7 @@ import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; -public class LibrariesUniqueTask extends TaskResult { +public class LibrariesUniqueTask extends Task { private final Version version; public LibrariesUniqueTask(Version version) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java index 311ffaa1a..b9d5e92b2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java @@ -45,7 +45,7 @@ import java.util.logging.Level; import static org.jackhuang.hmcl.util.DigestUtils.digest; import static org.jackhuang.hmcl.util.Hex.encodeHex; -public class LibraryDownloadTask extends Task { +public class LibraryDownloadTask extends Task { private FileDownloadTask task; protected final File jar; protected final DefaultCacheRepository cacheRepository; @@ -74,7 +74,7 @@ public class LibraryDownloadTask extends Task { } @Override - public Collection getDependents() { + public Collection> getDependents() { if (cached) return Collections.emptyList(); else return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java index d24bc5a6a..30024cd98 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java @@ -22,7 +22,6 @@ import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.util.Collection; @@ -33,11 +32,11 @@ import java.util.List; * * @author huangyuhui */ -public final class VersionJsonDownloadTask extends TaskResult { +public final class VersionJsonDownloadTask extends Task { private final String gameVersion; private final DefaultDependencyManager dependencyManager; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); private final VersionList gameVersionList; public VersionJsonDownloadTask(String gameVersion, DefaultDependencyManager dependencyManager) { @@ -52,12 +51,12 @@ public final class VersionJsonDownloadTask extends TaskResult { } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java index 9c3793fc4..2a14c2f79 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java @@ -19,7 +19,7 @@ package org.jackhuang.hmcl.download.game; import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.Version; -import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; @@ -30,7 +30,7 @@ import java.io.File; * * @author huangyuhui */ -public final class VersionJsonSaveTask extends TaskResult { +public final class VersionJsonSaveTask extends Task { private final DefaultGameRepository repository; private final Version version; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderBMCLVersionList.java index 7451bc2ea..da6f20c91 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderBMCLVersionList.java @@ -33,7 +33,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.Optional; /** * @@ -52,11 +51,11 @@ public final class LiteLoaderBMCLVersionList extends VersionList refreshAsync(DownloadProvider downloadProvider) { GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(LITELOADER_LIST))); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java index 558714f95..33cd7da2a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java @@ -23,7 +23,6 @@ import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.LibraryDownloadInfo; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.Lang; import java.util.Collection; @@ -36,13 +35,13 @@ import java.util.List; * * @author huangyuhui */ -public final class LiteLoaderInstallTask extends TaskResult { +public final class LiteLoaderInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final Version version; private final LiteLoaderRemoteVersion remote; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); public LiteLoaderInstallTask(DefaultDependencyManager dependencyManager, Version version, LiteLoaderRemoteVersion remoteVersion) { this.dependencyManager = dependencyManager; @@ -51,12 +50,12 @@ public final class LiteLoaderInstallTask extends TaskResult { } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java index bdc720408..f5d48441f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java @@ -33,7 +33,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.Optional; /** * @@ -52,11 +51,11 @@ public final class LiteLoaderVersionList extends VersionList refreshAsync(DownloadProvider downloadProvider) { GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(LITELOADER_LIST))); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java index 56bf747ed..0ff0f3815 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java @@ -46,11 +46,11 @@ public final class OptiFineBMCLVersionList extends VersionList refreshAsync(DownloadProvider downloadProvider) { GetTask task = new GetTask(NetworkUtils.toURL("http://bmclapi2.bangbang93.com/optifine/versionlist")); - return new Task() { + return new Task() { @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java index 716ddfad4..444430912 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java @@ -23,7 +23,6 @@ import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.LibraryDownloadInfo; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskResult; import org.jackhuang.hmcl.util.Lang; import java.util.Collection; @@ -35,13 +34,13 @@ import java.util.List; * * @author huangyuhui */ -public final class OptiFineInstallTask extends TaskResult { +public final class OptiFineInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final Version version; private final OptiFineRemoteVersion remote; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); public OptiFineInstallTask(DefaultDependencyManager dependencyManager, Version version, OptiFineRemoteVersion remoteVersion) { this.dependencyManager = dependencyManager; @@ -50,12 +49,12 @@ public final class OptiFineInstallTask extends TaskResult { } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java index 0aff52693..04fb45664 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java @@ -77,8 +77,8 @@ public interface GameRepository extends VersionProvider { */ void refreshVersions(); - default Task refreshVersionsAsync() { - return Task.of(this::refreshVersions); + default Task refreshVersionsAsync() { + return Task.runAsync(this::refreshVersions); } /** diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseCompletionTask.java index 9bac795b1..3808404ef 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseCompletionTask.java @@ -43,14 +43,14 @@ import java.util.stream.Collectors; * * @author huangyuhui */ -public final class CurseCompletionTask extends Task { +public final class CurseCompletionTask extends Task { private final DefaultGameRepository repository; private final ModManager modManager; private final String version; private CurseManifest manifest = null; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); /** * Constructor. @@ -86,12 +86,12 @@ public final class CurseCompletionTask extends Task { } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @@ -147,7 +147,7 @@ public final class CurseCompletionTask extends Task { // Let this task fail if the curse manifest has not been completed. // But continue other downloads. if (!flag.get() || notFound.get()) - dependencies.add(Task.of(() -> { + dependencies.add(Task.runAsync(() -> { if (notFound.get()) throw new CurseCompletionException(new FileNotFoundException()); else diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseInstallTask.java index 86fe2b715..77449cd5e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/CurseInstallTask.java @@ -38,7 +38,7 @@ import java.util.List; * * @author huangyuhui */ -public final class CurseInstallTask extends Task { +public final class CurseInstallTask extends Task { private final DefaultDependencyManager dependencyManager; private final DefaultGameRepository repository; @@ -48,8 +48,8 @@ public final class CurseInstallTask extends Task { private final String name; private final File run; private final ModpackConfiguration config; - private final List dependents = new LinkedList<>(); - private final List dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); /** * Constructor. @@ -99,12 +99,12 @@ public final class CurseInstallTask extends Task { } @Override - public Collection getDependents() { + public Collection> getDependents() { return dependents; } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return dependencies; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java index 33354e6cb..f7a05b10d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java @@ -33,7 +33,7 @@ import java.util.List; import static org.jackhuang.hmcl.util.DigestUtils.digest; import static org.jackhuang.hmcl.util.Hex.encodeHex; -public final class MinecraftInstanceTask extends Task { +public final class MinecraftInstanceTask extends Task { private final File zipFile; private final Charset encoding; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackInstallTask.java index 4a9473239..291909dcd 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackInstallTask.java @@ -31,7 +31,7 @@ import java.util.function.Predicate; import static org.jackhuang.hmcl.util.DigestUtils.digest; import static org.jackhuang.hmcl.util.Hex.encodeHex; -public class ModpackInstallTask extends Task { +public class ModpackInstallTask extends Task { private final File modpackFile; private final File dest; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java index 7adc8754d..608f81692 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java @@ -26,14 +26,14 @@ import java.nio.file.Path; import java.util.Collection; import java.util.Collections; -public class ModpackUpdateTask extends Task { +public class ModpackUpdateTask extends Task { private final DefaultGameRepository repository; private final String id; - private final Task updateTask; + private final Task updateTask; private final Path backupFolder; - public ModpackUpdateTask(DefaultGameRepository repository, String id, Task updateTask) { + public ModpackUpdateTask(DefaultGameRepository repository, String id, Task updateTask) { this.repository = repository; this.id = id; this.updateTask = updateTask; @@ -49,7 +49,7 @@ public class ModpackUpdateTask extends Task { } @Override - public Collection getDependencies() { + public Collection> getDependencies() { return Collections.singleton(updateTask); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java index 6095604ec..06d1571f6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java @@ -46,15 +46,15 @@ import java.util.Optional; * * @author huangyuhui */ -public final class MultiMCModpackInstallTask extends Task { +public final class MultiMCModpackInstallTask extends Task { private final File zipFile; private final Modpack modpack; private final MultiMCInstanceConfiguration manifest; private final String name; private final DefaultGameRepository repository; - private final List dependencies = new LinkedList<>(); - private final List dependents = new LinkedList<>(); + private final List> dependencies = new LinkedList<>(); + private final List> dependents = new LinkedList<>(); public MultiMCModpackInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, MultiMCInstanceConfiguration manifest, String name) { this.zipFile = zipFile; @@ -91,7 +91,7 @@ public final class MultiMCModpackInstallTask extends Task { } @Override - public List getDependencies() { + public List> getDependencies() { return dependencies; } @@ -126,7 +126,7 @@ public final class MultiMCModpackInstallTask extends Task { } @Override - public List getDependents() { + public List> getDependents() { return dependents; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CoupleTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CoupleTask.java deleted file mode 100644 index f9d87efe7..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CoupleTask.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2019 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.task; - -import org.jackhuang.hmcl.util.AutoTypingMap; -import org.jackhuang.hmcl.util.function.ExceptionalSupplier; - -import java.util.Collection; -import java.util.Collections; - -/** - * A task that combines two tasks and make sure [pred] runs before succ. - * - * @author huangyuhui - */ -final class CoupleTask extends Task { - - private final boolean relyingOnDependents; - private final Task pred; - private Task succ; - private final ExceptionalSupplier supplier; - - /** - * A task that combines two tasks and make sure pred runs before succ. - * - * @param pred the task that runs before supplier. - * @param supplier a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. - * @param relyingOnDependents true if this task chain will be broken when task pred fails. - */ - CoupleTask(Task pred, ExceptionalSupplier supplier, boolean relyingOnDependents) { - this.pred = pred; - this.supplier = supplier; - this.relyingOnDependents = relyingOnDependents; - - setSignificance(TaskSignificance.MODERATE); - setName(supplier.toString()); - } - - @Override - public void execute() throws Exception { - setName(supplier.toString()); - succ = supplier.get(); - } - - @Override - public Collection getDependents() { - return pred == null ? Collections.emptySet() : Collections.singleton(pred); - } - - @Override - public Collection getDependencies() { - return succ == null ? Collections.emptySet() : Collections.singleton(succ); - } - - @Override - public boolean isRelyingOnDependents() { - return relyingOnDependents; - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java index 7829d02b0..670c4b6d5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java @@ -47,7 +47,7 @@ import static org.jackhuang.hmcl.util.DigestUtils.getDigest; * * @author huangyuhui */ -public class FileDownloadTask extends Task { +public class FileDownloadTask extends Task { public static class IntegrityCheck { private String algorithm; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java index 376d3914a..24fd5738b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java @@ -36,33 +36,27 @@ import static java.nio.charset.StandardCharsets.UTF_8; /** * - * @author huang + * @author huangyuhui */ -public final class GetTask extends TaskResult { +public final class GetTask extends Task { private final URL url; private final Charset charset; private final int retry; - private final String id; private CacheRepository repository = CacheRepository.getInstance(); public GetTask(URL url) { - this(url, ID); + this(url, UTF_8); } - public GetTask(URL url, String id) { - this(url, id, UTF_8); + public GetTask(URL url, Charset charset) { + this(url, charset, 5); } - public GetTask(URL url, String id, Charset charset) { - this(url, id, charset, 5); - } - - public GetTask(URL url, String id, Charset charset, int retry) { + public GetTask(URL url, Charset charset, int retry) { this.url = url; this.charset = charset; this.retry = retry; - this.id = id; setName(url.toString()); } @@ -138,9 +132,4 @@ public final class GetTask extends TaskResult { throw new DownloadException(url, exception); } - /** - * The default task result ID. - */ - public static final String ID = "http_get"; - } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/ParallelTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/ParallelTask.java deleted file mode 100644 index 00844573b..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/ParallelTask.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2019 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.task; - -import java.util.Arrays; -import java.util.Collection; - -/** - * The tasks that provides a way to execute tasks parallelly. - * Fails when some of {@link #tasks} failed. - * - * @author huangyuhui - */ -public final class ParallelTask extends Task { - - private final Collection tasks; - - /** - * Constructor. - * - * @param tasks the tasks that can be executed parallelly. - */ - public ParallelTask(Task... tasks) { - this.tasks = Arrays.asList(tasks); - setSignificance(TaskSignificance.MINOR); - } - - public ParallelTask(Collection tasks) { - this.tasks = tasks; - setSignificance(TaskSignificance.MINOR); - } - - @Override - public void execute() { - } - - @Override - public Collection getDependents() { - return tasks; - } - -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTask.java deleted file mode 100644 index f8bd7f3d9..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTask.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2019 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.task; - -import org.jackhuang.hmcl.util.function.ExceptionalRunnable; - -/** - * - * @author huangyuhui - */ -class SimpleTask extends Task { - - private final ExceptionalRunnable closure; - private final Scheduler scheduler; - - public SimpleTask(String name, ExceptionalRunnable closure, Scheduler scheduler) { - this.closure = closure; - this.scheduler = scheduler; - - if (name == null) { - setSignificance(TaskSignificance.MINOR); - setName(closure.toString()); - } else { - setName(name); - } - } - - @Override - public Scheduler getScheduler() { - return scheduler; - } - - @Override - public void execute() throws Exception { - closure.run(); - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTaskResult.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTaskResult.java deleted file mode 100644 index 22111f654..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/SimpleTaskResult.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2019 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.task; - -import org.jackhuang.hmcl.util.AutoTypingMap; -import org.jackhuang.hmcl.util.function.ExceptionalFunction; -import org.jackhuang.hmcl.util.function.ExceptionalSupplier; - -import java.util.concurrent.Callable; - -/** - * - * @author huangyuhui - */ -class SimpleTaskResult extends TaskResult { - - private final Callable callable; - - public SimpleTaskResult(Callable callable) { - this.callable = callable; - } - - public SimpleTaskResult(ExceptionalSupplier supplier) { - this.callable = supplier.toCallable(); - } - - @Override - public void execute() throws Exception { - setResult(callable.call()); - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index 358184f8a..292ae08f6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -27,13 +27,16 @@ import org.jackhuang.hmcl.util.InvocationDispatcher; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.ReflectionHelper; import org.jackhuang.hmcl.util.function.ExceptionalConsumer; +import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalRunnable; import org.jackhuang.hmcl.util.function.ExceptionalSupplier; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; +import java.util.function.Consumer; import java.util.logging.Level; /** @@ -41,15 +44,15 @@ import java.util.logging.Level; * * @author huangyuhui */ -public abstract class Task { +public abstract class Task { private final EventManager onDone = new EventManager<>(); - private TaskSignificance significance = TaskSignificance.MAJOR; - /** * True if not logging when executing this task. */ + private TaskSignificance significance = TaskSignificance.MAJOR; + public final TaskSignificance getSignificance() { return significance; } @@ -58,6 +61,7 @@ public abstract class Task { this.significance = significance; } + // state private TaskState state = TaskState.READY; public TaskState getState() { @@ -68,6 +72,7 @@ public abstract class Task { this.state = state; } + // last exception private Exception lastException; public Exception getLastException() { @@ -85,6 +90,7 @@ public abstract class Task { return Schedulers.defaultScheduler(); } + // dependents succeeded private boolean dependentsSucceeded = false; public boolean isDependentsSucceeded() { @@ -95,6 +101,7 @@ public abstract class Task { dependentsSucceeded = true; } + // dependencies succeeded private boolean dependenciesSucceeded = false; public boolean isDependenciesSucceeded() { @@ -123,17 +130,49 @@ public abstract class Task { return true; } + // name private String name = getClass().getName(); public String getName() { return name; } - public Task setName(String name) { + public Task setName(String name) { this.name = name; return this; } + // result + private T result; + private Consumer resultConsumer; + + /** + * Returns the result of this task. + * + * The result will be generated only if the execution is completed. + */ + public T getResult() { + return result; + } + + protected void setResult(T result) { + this.result = result; + if (resultConsumer != null) + resultConsumer.accept(result); + } + + /** + * Sync the result of this task by given action. + * + * @param action the action to perform when result of this task changed + * @return this Task + */ + public Task storeTo(Consumer action) { + this.resultConsumer = action; + return this; + } + + // execution public boolean doPreExecute() { return false; } @@ -171,7 +210,7 @@ public abstract class Task { /** * The collection of sub-tasks that should execute **before** this task running. */ - public Collection getDependents() { + public Collection> getDependents() { return Collections.emptySet(); } @@ -179,7 +218,7 @@ public abstract class Task { * The collection of sub-tasks that should execute **after** this task running. * Will not be executed if execution fails. */ - public Collection getDependencies() { + public Collection> getDependencies() { return Collections.emptySet(); } @@ -232,15 +271,15 @@ public abstract class Task { if (getSignificance().shouldLog()) Logging.LOG.log(Level.FINE, "Executing task: " + getName()); - for (Task task : getDependents()) + for (Task task : getDependents()) doSubTask(task); execute(); - for (Task task : getDependencies()) + for (Task task : getDependencies()) doSubTask(task); onDone.fireEvent(new TaskEvent(this, this, false)); } - private void doSubTask(Task task) throws Exception { + private void doSubTask(Task task) throws Exception { message.bind(task.message); progress.bind(task.progress); task.run(); @@ -273,61 +312,240 @@ public abstract class Task { return executor().test(); } - public final Task then(Task b) { - return then(convert(b)); - } - - public final Task then(ExceptionalSupplier b) { - return new CoupleTask(this, b, true); + /** + * Returns a new Task that, when this task completes + * normally, is executed using the default Scheduler, with this + * task's result as the argument to the supplied function. + * + * @param fn the function to use to compute the value of the returned Task + * @param the function's return type + * @return the new Task + */ + public Task thenApply(ExceptionalFunction fn) { + return thenApply(Schedulers.defaultScheduler(), fn); } /** - * Returns a new TaskResult that, when this task completes + * Returns a new Task that, when this task completes + * normally, is executed using the supplied Scheduler, with this + * task's result as the argument to the supplied function. + * + * @param scheduler the executor to use for asynchronous execution + * @param fn the function to use to compute the value of the returned Task + * @param the function's return type + * @return the new Task + */ + public Task thenApply(Scheduler scheduler, ExceptionalFunction fn) { + return thenApply(getCaller(), scheduler, fn); + } + + /** + * Returns a new Task that, when this task completes + * normally, is executed using the supplied Scheduler, with this + * task's result as the argument to the supplied function. + * + * @param name the name of this new Task for displaying + * @param scheduler the executor to use for asynchronous execution + * @param fn the function to use to compute the value of the returned Task + * @param the function's return type + * @return the new Task + */ + public Task thenApply(String name, Scheduler scheduler, ExceptionalFunction fn) { + return new UniApply<>(name, scheduler, fn); + } + + /** + * Returns a new Task that, when this task completes + * normally, is executed using the default Scheduler, with this + * task's result as the argument to the supplied action. + * + * @param action the action to perform before completing the + * returned Task + * @return the new Task + */ + public Task thenAccept(ExceptionalConsumer action) { + return thenAccept(Schedulers.defaultScheduler(), action); + } + + /** + * Returns a new Task that, when this task completes + * normally, is executed using the supplied Scheduler, with this + * task's result as the argument to the supplied action. + * + * @param action the action to perform before completing the returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task thenAccept(Scheduler scheduler, ExceptionalConsumer action) { + return thenAccept(getCaller(), scheduler, action); + } + + /** + * Returns a new Task that, when this task completes + * normally, is executed using the supplied Scheduler, with this + * task's result as the argument to the supplied action. + * + * @param name the name of this new Task for displaying + * @param action the action to perform before completing the returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task thenAccept(String name, Scheduler scheduler, ExceptionalConsumer action) { + return thenApply(name, scheduler, result -> { + action.accept(result); + return null; + }); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the default Scheduler. + * + * @param action the action to perform before completing the + * returned Task + * @return the new Task + */ + public Task thenRun(ExceptionalRunnable action) { + return thenRun(Schedulers.defaultScheduler(), action); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the supplied Scheduler. + * + * @param action the action to perform before completing the + * returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task thenRun(Scheduler scheduler, ExceptionalRunnable action) { + return thenRun(getCaller(), scheduler, action); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the supplied Scheduler. + * + * @param name the name of this new Task for displaying + * @param action the action to perform before completing the + * returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task thenRun(String name, Scheduler scheduler, ExceptionalRunnable action) { + return thenApply(name, scheduler, ignore -> { + action.run(); + return null; + }); + } + + /** + * Returns a new Task that, when this task completes * normally, is executed using the default Scheduler. * - * @param fn the function to use to compute the value of the returned TaskResult + * @param fn the function to use to compute the value of the returned Task * @param the function's return type - * @return the new TaskResult + * @return the new Task */ - public final TaskResult thenSupply(Callable fn) { - return thenCompose(() -> Task.ofResult(fn)); + public final Task thenSupply(Callable fn) { + return thenCompose(() -> Task.supplyAsync(fn)); } /** - * Returns a new TaskResult that, when this task completes + * Returns a new Task that, when this task completes + * normally, is executed using the default Scheduler. + * + * @param name the name of this new Task for displaying + * @param fn the function to use to compute the value of the returned Task + * @param the function's return type + * @return the new Task + */ + public final Task thenSupply(String name, Callable fn) { + return thenCompose(() -> Task.supplyAsync(name, fn)); + } + + /** + * Returns a new Task that, when this task completes * normally, is executed. * - * @param fn the function returning a new TaskResult - * @param the type of the returned TaskResult's result - * @return the TaskResult + * @param other the another Task + * @param the type of the returned Task's result + * @return the Task */ - public final TaskResult thenCompose(ExceptionalSupplier, ?> fn) { - return new TaskResult() { - TaskResult then; - - @Override - public Collection getDependents() { - return Collections.singleton(Task.this); - } - - @Override - public void execute() throws Exception { - then = fn.get().storeTo(this::setResult); - } - - @Override - public Collection getDependencies() { - return then == null ? Collections.emptyList() : Collections.singleton(then); - } - }; + public final Task thenCompose(Task other) { + return thenCompose(() -> other); + } + + /** + * Returns a new Task that, when this task completes + * normally, is executed. + * + * @param fn the function returning a new Task + * @param the type of the returned Task's result + * @return the Task + */ + public final Task thenCompose(ExceptionalSupplier, ?> fn) { + return new UniCompose<>(fn, true); } - public final Task with(Task b) { - return with(convert(b)); + /** + * Returns a new Task that, when this task completes + * normally, is executed with result of this task as the argument + * to the supplied function. + * + * @param fn the function returning a new Task + * @param the type of the returned Task's result + * @return the Task + */ + public Task thenCompose(ExceptionalFunction, E> fn) { + return new UniCompose<>(fn, true); } - public final Task with(ExceptionalSupplier b) { - return new CoupleTask(this, b, false); + public final Task withCompose(Task other) { + return withCompose(() -> other); + } + + public final Task withCompose(ExceptionalSupplier, E> fn) { + return new UniCompose<>(fn, false); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the default Scheduler. + * + * @param action the action to perform before completing the + * returned Task + * @return the new Task + */ + public Task withRun(ExceptionalRunnable action) { + return withRun(Schedulers.defaultScheduler(), action); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the supplied Scheduler. + * + * @param action the action to perform before completing the + * returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task withRun(Scheduler scheduler, ExceptionalRunnable action) { + return withRun(getCaller(), scheduler, action); + } + + /** + * Returns a new Task that, when this task completes + * normally, executes the given action using the supplied Scheduler. + * + * @param name the name of this new Task for displaying + * @param action the action to perform before completing the + * returned Task + * @param scheduler the executor to use for asynchronous execution + * @return the new Task + */ + public Task withRun(String name, Scheduler scheduler, ExceptionalRunnable action) { + return new UniCompose<>(() -> Task.runAsync(name, scheduler, action), false); } /** @@ -344,7 +562,7 @@ public abstract class Task { * @param action the action to perform * @return the new Task */ - public final Task whenComplete(FinalizedCallback action) { + public final Task whenComplete(FinalizedCallback action) { return whenComplete(Schedulers.defaultScheduler(), action); } @@ -364,8 +582,8 @@ public abstract class Task { * @param scheduler the executor to use for asynchronous execution * @return the new Task */ - public final Task whenComplete(Scheduler scheduler, FinalizedCallback action) { - return new Task() { + public final Task whenComplete(Scheduler scheduler, FinalizedCallback action) { + return new Task() { { setSignificance(TaskSignificance.MODERATE); } @@ -389,7 +607,7 @@ public abstract class Task { } @Override - public Collection getDependents() { + public Collection> getDependents() { return Collections.singleton(Task.this); } @@ -400,6 +618,25 @@ public abstract class Task { }.setName(getCaller()); } + /** + * Returns a new Task with the same exception as this task, that executes + * the given action when this task completes. + * + *

When this task is complete, the given action is invoked with the + * result (or {@code null} if none), a boolean value represents the + * execution status of this task, and the exception (or {@code null} + * if none) of this task as arguments. The returned task is completed + * when the action returns. If the supplied action itself encounters an + * exception, then the returned task exceptionally completes with this + * exception unless this task also completed exceptionally. + * + * @param action the action to perform + * @return the new Task + */ + public Task whenComplete(Scheduler scheduler, FinalizedCallbackWithResult action) { + return whenComplete(scheduler, ((isDependentSucceeded, exception) -> action.execute(getResult(), isDependentSucceeded, exception))); + } + /** * Returns a new Task with the same exception as this task, that executes * the given actions when this task completes. @@ -415,7 +652,7 @@ public abstract class Task { * @param failure the action to perform when this task exceptionally returned * @return the new Task */ - public final Task whenComplete(Scheduler scheduler, ExceptionalRunnable success, ExceptionalConsumer failure) { + public final Task whenComplete(Scheduler scheduler, ExceptionalRunnable success, ExceptionalConsumer failure) { return whenComplete(scheduler, (isDependentSucceeded, exception) -> { if (isDependentSucceeded) { if (success != null) @@ -433,44 +670,114 @@ public abstract class Task { }); } - public static Task of(ExceptionalRunnable closure) { - return of(Schedulers.defaultScheduler(), closure); + /** + * Returns a new Task with the same exception as this task, that executes + * the given actions when this task completes. + * + *

When this task is complete, the given success action is invoked with + * the result, the given failure action is invoked with the exception of + * this task. The returned task is completed when the action returns. If + * the supplied action itself encounters an exception, then the returned + * task exceptionally completes with this exception unless this task also + * completed exceptionally. + * + * @param success the action to perform when this task successfully completed + * @param failure the action to perform when this task exceptionally returned + * @return the new Task + */ + public Task whenComplete(Scheduler scheduler, ExceptionalConsumer success, ExceptionalConsumer failure) { + return whenComplete(scheduler, () -> success.accept(getResult()), failure); } - public static Task of(String name, ExceptionalRunnable closure) { - return of(name, Schedulers.defaultScheduler(), closure); + public static Task runAsync(ExceptionalRunnable closure) { + return runAsync(Schedulers.defaultScheduler(), closure); } - public static Task of(Scheduler scheduler, ExceptionalRunnable closure) { - return of(getCaller(), scheduler, closure); + public static Task runAsync(String name, ExceptionalRunnable closure) { + return runAsync(name, Schedulers.defaultScheduler(), closure); } - public static Task of(String name, Scheduler scheduler, ExceptionalRunnable closure) { - return new SimpleTask(name, closure, scheduler); + public static Task runAsync(Scheduler scheduler, ExceptionalRunnable closure) { + return runAsync(getCaller(), scheduler, closure); } - public static Task ofThen(ExceptionalSupplier b) { - return new CoupleTask(null, b, true); + public static Task runAsync(String name, Scheduler scheduler, ExceptionalRunnable closure) { + return new SimpleTask<>(closure.toCallable(), scheduler).setName(name); } - public static TaskResult ofResult(Callable callable) { - return ofResult(getCaller(), callable); - } + public static Task composeAsync(ExceptionalSupplier, ?> fn) { + return new Task() { + Task then; - public static TaskResult ofResult(String name, Callable callable) { - return new SimpleTaskResult<>(callable).setName(name); - } - - private static ExceptionalSupplier convert(Task t) { - return new ExceptionalSupplier() { @Override - public Task get() { - return t; + public void execute() throws Exception { + then = fn.get(); + if (then != null) + then.storeTo(this::setResult); } @Override - public String toString() { - return t.getName(); + public Collection> getDependencies() { + return then == null ? Collections.emptySet() : Collections.singleton(then); + } + }; + } + + public static Task supplyAsync(Callable callable) { + return supplyAsync(getCaller(), callable); + } + + public static Task supplyAsync(Scheduler scheduler, Callable callable) { + return supplyAsync(getCaller(), scheduler, callable); + } + + public static Task supplyAsync(String name, Callable callable) { + return supplyAsync(name, Schedulers.defaultScheduler(), callable); + } + + public static Task supplyAsync(String name, Scheduler scheduler, Callable callable) { + return new SimpleTask<>(callable, scheduler).setName(name); + } + + /** + * Returns a new Task that is completed when all of the given Tasks + * complete. If any of the given Tasks complete exceptionally, + * then the returned Task also does so. Otherwise, the results, if + * any, of the given Tasks are not reflected in the returned Task, + * but may be obtained by inspecting them individually. If no Tasks + * are provided, returns a Task completed with the value {@code null}. + * + * @param tasks the Tasks + * @return a new Task that is completed when all of the given Tasks complete + */ + public static Task allOf(Task... tasks) { + return allOf(Arrays.asList(tasks)); + } + + /** + * Returns a new Task that is completed when all of the given Tasks + * complete. If any of the given Tasks complete exceptionally, + * then the returned Task also does so. Otherwise, the results, if + * any, of the given Tasks are not reflected in the returned Task, + * but may be obtained by inspecting them individually. If no Tasks + * are provided, returns a Task completed with the value {@code null}. + * + * @param tasks the Tasks + * @return a new Task that is completed when all of the given Tasks complete + */ + public static Task allOf(Collection> tasks) { + return new Task() { + { + setSignificance(TaskSignificance.MINOR); + } + + @Override + public void execute() { + } + + @Override + public Collection> getDependents() { + return tasks; } }; } @@ -501,7 +808,118 @@ public abstract class Task { void execute(boolean isDependentSucceeded, Exception exception) throws Exception; } - static String getCaller() { + public interface FinalizedCallbackWithResult { + void execute(T result, boolean isDependentSucceeded, Exception exception) throws Exception; + } + + private static String getCaller() { return ReflectionHelper.getCaller(packageName -> !"org.jackhuang.hmcl.task".equals(packageName)).toString(); } + + private static final class SimpleTask extends Task { + + private final Callable callable; + private final Scheduler scheduler; + + SimpleTask(Callable callable, Scheduler scheduler) { + this.callable = callable; + this.scheduler = scheduler; + } + + @Override + public Scheduler getScheduler() { + return scheduler; + } + + @Override + public void execute() throws Exception { + setResult(callable.call()); + } + } + + private class UniApply extends Task { + private final Scheduler scheduler; + private final ExceptionalFunction callable; + + UniApply(String name, Scheduler scheduler, ExceptionalFunction callable) { + this.scheduler = scheduler; + this.callable = callable; + + setName(name); + } + + @Override + public Collection> getDependents() { + return Collections.singleton(Task.this); + } + + @Override + public Scheduler getScheduler() { + return scheduler; + } + + @Override + public void execute() throws Exception { + setResult(callable.apply(Task.this.getResult())); + } + } + + /** + * A task that combines two tasks and make sure [pred] runs before succ. + * + * @author huangyuhui + */ + private final class UniCompose extends Task { + + private final boolean relyingOnDependents; + private Task succ; + private final ExceptionalFunction, ?> fn; + + /** + * A task that combines two tasks and make sure pred runs before succ. + * + * @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. + * @param relyingOnDependents true if this task chain will be broken when task pred fails. + */ + UniCompose(ExceptionalSupplier, ?> fn, boolean relyingOnDependents) { + this(result -> fn.get(), relyingOnDependents); + } + + /** + * A task that combines two tasks and make sure pred runs before succ. + * + * @param fn a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. + * @param relyingOnDependents true if this task chain will be broken when task pred fails. + */ + UniCompose(ExceptionalFunction, ?> fn, boolean relyingOnDependents) { + this.fn = fn; + this.relyingOnDependents = relyingOnDependents; + + setSignificance(TaskSignificance.MODERATE); + setName(fn.toString()); + } + + @Override + public void execute() throws Exception { + setName(fn.toString()); + succ = fn.apply(Task.this.getResult()); + if (succ != null) + succ.storeTo(this::setResult); + } + + @Override + public Collection> getDependents() { + return Collections.singleton(Task.this); + } + + @Override + public Collection> getDependencies() { + return succ == null ? Collections.emptySet() : Collections.singleton(succ); + } + + @Override + public boolean isRelyingOnDependents() { + return relyingOnDependents; + } + } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskEvent.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskEvent.java index 747879912..94edbede0 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskEvent.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskEvent.java @@ -25,16 +25,16 @@ import org.jackhuang.hmcl.event.Event; */ public class TaskEvent extends Event { - private final Task task; + private final Task task; private final boolean failed; - public TaskEvent(Object source, Task task, boolean failed) { + public TaskEvent(Object source, Task task, boolean failed) { super(source); this.task = task; this.failed = failed; } - public Task getTask() { + public Task getTask() { return task; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java index 3cbf487af..b7b5be421 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java @@ -22,7 +22,6 @@ import org.jackhuang.hmcl.util.function.ExceptionalRunnable; import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; @@ -32,15 +31,13 @@ import java.util.logging.Level; */ public final class TaskExecutor { - private final Task firstTask; + private final Task firstTask; private final List taskListeners = new LinkedList<>(); - private boolean canceled = false; private Exception lastException; private final AtomicInteger totTask = new AtomicInteger(0); - private final ConcurrentLinkedQueue> workerQueue = new ConcurrentLinkedQueue<>(); - private Scheduler scheduler = Schedulers.newThread(); + private CompletableFuture future; - public TaskExecutor(Task task) { + public TaskExecutor(Task task) { this.firstTask = task; } @@ -48,222 +45,204 @@ public final class TaskExecutor { taskListeners.add(taskListener); } - public boolean isCanceled() { - return canceled; - } - public Exception getLastException() { return lastException; } - public void setScheduler(Scheduler scheduler) { - this.scheduler = Objects.requireNonNull(scheduler); - } - public TaskExecutor start() { taskListeners.forEach(TaskListener::onStart); - workerQueue.add(scheduler.schedule(() -> { - boolean flag = executeTasks(Collections.singleton(firstTask)); - taskListeners.forEach(it -> it.onStop(flag, this)); - })); + future = executeTasks(Collections.singleton(firstTask)) + .thenApplyAsync(exception -> { + boolean success = exception == null; + taskListeners.forEach(it -> it.onStop(success, this)); + return success; + }) + .exceptionally(e -> { + Lang.handleUncaughtException(e instanceof UncheckedThrowable ? e.getCause() : e); + return false; + }); return this; } public boolean test() { - taskListeners.forEach(TaskListener::onStart); - AtomicBoolean flag = new AtomicBoolean(true); - Future future = scheduler.schedule(() -> { - flag.set(executeTasks(Collections.singleton(firstTask))); - taskListeners.forEach(it -> it.onStop(flag.get(), this)); - }); - workerQueue.add(future); + start(); try { - future.get(); + return future.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException | CancellationException e) { } - return flag.get(); + return false; } /** * Cancel the subscription ant interrupt all tasks. */ public synchronized void cancel() { - canceled = true; - - while (!workerQueue.isEmpty()) { - Future future = workerQueue.poll(); - if (future != null) - future.cancel(true); + if (future == null) { + throw new IllegalStateException("Cannot cancel a not started TaskExecutor"); } + + future.cancel(true); } - private boolean executeTasks(Collection tasks) throws InterruptedException { - if (tasks.isEmpty()) - return true; + private CompletableFuture executeTasks(Collection> tasks) { + if (tasks == null || tasks.isEmpty()) + return CompletableFuture.completedFuture(null); - totTask.addAndGet(tasks.size()); - AtomicBoolean success = new AtomicBoolean(true); - CountDownLatch latch = new CountDownLatch(tasks.size()); - for (Task task : tasks) { - if (canceled) - return false; - Invoker invoker = new Invoker(task, latch, success); - try { - Future future = scheduler.schedule(invoker); - if (future != null) - workerQueue.add(future); - } catch (RejectedExecutionException e) { - throw new InterruptedException(); - } - } + return CompletableFuture.completedFuture(null) + .thenComposeAsync(unused -> { + totTask.addAndGet(tasks.size()); - if (canceled) - return false; + return CompletableFuture.allOf(tasks.stream() + .map(task -> CompletableFuture.completedFuture(null) + .thenComposeAsync(unused2 -> executeTask(task)) + ).toArray(CompletableFuture[]::new)); + }) + .thenApplyAsync(unused -> (Exception) null) + .exceptionally(throwable -> { + if (throwable instanceof Exception) { + return (Exception) throwable; + } else { + // If an error occurred, we just rethrow it. + throw new UncheckedThrowable(throwable); + } + }); + } + private static void scheduleTo(Scheduler scheduler, ExceptionalRunnable runnable) { + scheduleTo(scheduler, runnable, null); + } + + private static void scheduleTo(Scheduler scheduler, ExceptionalRunnable runnable, Runnable finalize) { try { - latch.await(); + scheduler.schedule(runnable).get(); + } catch (ExecutionException e) { + if (e.getCause() instanceof Exception) + rethrow(e.getCause()); + else + throw new UncheckedException(e); } catch (InterruptedException e) { - return false; + throw new UncheckedException(e); + } finally { + if (finalize != null) + finalize.run(); } - return success.get() && !canceled; } - private boolean executeTask(Task task) { - if (canceled) { - task.setState(Task.TaskState.FAILED); - task.setLastException(new CancellationException()); - return false; - } + private CompletableFuture executeTask(Task task) { + return CompletableFuture.completedFuture(null).thenComposeAsync(unused -> { + task.setState(Task.TaskState.READY); - task.setState(Task.TaskState.READY); + if (task.getSignificance().shouldLog()) + Logging.LOG.log(Level.FINE, "Executing task: " + task.getName()); - if (task.getSignificance().shouldLog()) - Logging.LOG.log(Level.FINE, "Executing task: " + task.getName()); + taskListeners.forEach(it -> it.onReady(task)); - taskListeners.forEach(it -> it.onReady(task)); - - boolean flag = false; - - try { if (task.doPreExecute()) { - try { - task.getScheduler().schedule(task::preExecute).get(); - } catch (ExecutionException e) { - if (e.getCause() instanceof Exception) - throw (Exception) e.getCause(); - else - throw e; - } + scheduleTo(task.getScheduler(), task::preExecute); } - Collection dependents = task.getDependents(); - boolean doDependentsSucceeded = executeTasks(dependents); - Exception dependentsException = dependents.stream().map(Task::getLastException).filter(Objects::nonNull).findAny().orElse(null); - if (!doDependentsSucceeded && task.isRelyingOnDependents() || canceled) { + return executeTasks(task.getDependents()); + }).thenComposeAsync(dependentsException -> { + boolean isDependentsSucceeded = dependentsException == null; + + if (!isDependentsSucceeded && task.isRelyingOnDependents()) { task.setLastException(dependentsException); - throw new CancellationException(); + rethrow(dependentsException); } - if (doDependentsSucceeded) + if (isDependentsSucceeded) task.setDependentsSucceeded(); - try { - task.getScheduler().schedule(() -> { - task.setState(Task.TaskState.RUNNING); - taskListeners.forEach(it -> it.onRunning(task)); - task.execute(); - }).get(); - } catch (ExecutionException e) { - if (e.getCause() instanceof Exception) - throw (Exception) e.getCause(); - else - throw e; - } finally { - task.setState(Task.TaskState.EXECUTED); - } + scheduleTo(task.getScheduler(), () -> { + task.setState(Task.TaskState.RUNNING); + taskListeners.forEach(it -> it.onRunning(task)); + task.execute(); + }, () -> task.setState(Task.TaskState.EXECUTED)); - Collection dependencies = task.getDependencies(); - boolean doDependenciesSucceeded = executeTasks(dependencies); - Exception dependenciesException = dependencies.stream().map(Task::getLastException).filter(Objects::nonNull).findAny().orElse(null); + return executeTasks(task.getDependencies()); + }).thenApplyAsync(dependenciesException -> { + boolean isDependenciesSucceeded = dependenciesException == null; - if (doDependenciesSucceeded) + if (isDependenciesSucceeded) task.setDependenciesSucceeded(); if (task.doPostExecute()) { - try { - task.getScheduler().schedule(task::postExecute).get(); - } catch (ExecutionException e) { - if (e.getCause() instanceof Exception) - throw (Exception) e.getCause(); - else - throw e; - } + scheduleTo(task.getScheduler(), task::postExecute); } - if (!doDependenciesSucceeded && task.isRelyingOnDependencies()) { + if (!isDependenciesSucceeded && task.isRelyingOnDependencies()) { Logging.LOG.severe("Subtasks failed for " + task.getName()); task.setLastException(dependenciesException); - throw new CancellationException(); + rethrow(dependenciesException); } - flag = true; 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)); - } catch (InterruptedException e) { - task.setLastException(e); - 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, e)); - } catch (CancellationException | RejectedExecutionException e) { - if (task.getLastException() == null) + + task.setState(Task.TaskState.SUCCEEDED); + + return null; + }).exceptionally(throwable -> { + if (!(throwable instanceof Exception)) + throw new UncheckedThrowable(throwable); + Exception e = throwable instanceof UncheckedException ? (Exception) throwable.getCause() : (Exception) throwable; + if (e instanceof InterruptedException) { task.setLastException(e); - } catch (Exception e) { - task.setLastException(e); - lastException = e; - if (task.getSignificance().shouldLog()) { - Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e); + 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, e)); + } else if (e instanceof CancellationException || e instanceof RejectedExecutionException) { + if (task.getLastException() == null) + task.setLastException(e); + } else { + task.setLastException(e); + lastException = 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)); } - task.onDone().fireEvent(new TaskEvent(this, task, true)); - taskListeners.forEach(it -> it.onFailed(task, e)); - } - task.setState(flag ? Task.TaskState.SUCCEEDED : Task.TaskState.FAILED); - return flag; + + task.setState(Task.TaskState.FAILED); + + throw new UncheckedException(e); + }); } public int getRunningTasks() { return totTask.get(); } - private class Invoker implements ExceptionalRunnable { + private static class UncheckedException extends RuntimeException { - private final Task task; - private final CountDownLatch latch; - private final AtomicBoolean success; - - public Invoker(Task task, CountDownLatch latch, AtomicBoolean success) { - this.task = task; - this.latch = latch; - this.success = success; + UncheckedException(Exception exception) { + super(exception); } + } - @Override - public void run() { - try { - Thread.currentThread().setName(task.getName()); - if (!executeTask(task)) - success.set(false); - } finally { - latch.countDown(); - } + private static class UncheckedThrowable extends RuntimeException { + + UncheckedThrowable(Throwable throwable) { + super(throwable); } + } + private static void rethrow(Throwable e) { + if (e instanceof RuntimeException) { // including UncheckedException and UncheckedThrowable + throw (RuntimeException) e; + } else if (e instanceof Exception) { + throw new UncheckedException((Exception) e); + } else { + throw new UncheckedThrowable(e); + } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskListener.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskListener.java index 89bb84895..b1386aa05 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskListener.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskListener.java @@ -28,16 +28,16 @@ public abstract class TaskListener implements EventListener { public void onStart() { } - public void onReady(Task task) { + public void onReady(Task task) { } - public void onRunning(Task task) { + public void onRunning(Task task) { } - public void onFinished(Task task) { + public void onFinished(Task task) { } - public void onFailed(Task task, Throwable throwable) { + public void onFailed(Task task, Throwable throwable) { onFinished(task); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskResult.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskResult.java deleted file mode 100644 index cc8a3485c..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskResult.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2019 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.task; - -import org.jackhuang.hmcl.util.function.ExceptionalConsumer; -import org.jackhuang.hmcl.util.function.ExceptionalFunction; - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Consumer; - -/** - * A task that has a result. - * - * @author huangyuhui - */ -public abstract class TaskResult extends Task { - - private T result; - private Consumer resultConsumer; - - @Override - public TaskResult setName(String name) { - super.setName(name); - return this; - } - - /** - * Returns the result of this task. - * - * The result will be generated only if the execution is completed. - */ - public T getResult() { - return result; - } - - protected void setResult(T result) { - this.result = result; - if (resultConsumer != null) - resultConsumer.accept(result); - } - - /** - * Sync the result of this task by given action. - * - * @param action the action to perform when result of this task changed - * @return this TaskResult - */ - public TaskResult storeTo(Consumer action) { - this.resultConsumer = action; - return this; - } - - /** - * Returns a new TaskResult that, when this task completes - * normally, is executed with result of this task as the argument - * to the supplied function. - * - * @param fn the function returning a new TaskResult - * @param the type of the returned TaskResult's result - * @return the TaskResult - */ - public TaskResult thenCompose(ExceptionalFunction, E> fn) { - return new TaskResult() { - TaskResult then; - - @Override - public Collection getDependents() { - return Collections.singleton(TaskResult.this); - } - - @Override - public void execute() throws Exception { - then = fn.apply(TaskResult.this.getResult()).storeTo(this::setResult); - } - - @Override - public Collection getDependencies() { - return then == null ? Collections.emptyList() : Collections.singleton(then); - } - }; - } - - /** - * Returns a new Task that, when this task completes - * normally, is executed with this task as the argument - * to the supplied function. - * - * @param fn the function returning a new Task - * @return the Task - */ - public Task then(ExceptionalFunction fn) { - return new CoupleTask(this, () -> fn.apply(getResult()), true); - } - - /** - * Returns a new TaskResult that, when this task completes - * normally, is executed using the default Scheduler, with this - * task's result as the argument to the supplied function. - * - * @param fn the function to use to compute the value of the returned TaskResult - * @param the function's return type - * @return the new TaskResult - */ - public TaskResult thenApply(ExceptionalFunction fn) { - return thenApply(Schedulers.defaultScheduler(), fn); - } - - /** - * Returns a new TaskResult that, when this task completes - * normally, is executed using the supplied Scheduler, with this - * task's result as the argument to the supplied function. - * - * @param scheduler the executor to use for asynchronous execution - * @param fn the function to use to compute the value of the returned TaskResult - * @param the function's return type - * @return the new TaskResult - */ - public TaskResult thenApply(Scheduler scheduler, ExceptionalFunction fn) { - return thenApply(getCaller(), scheduler, fn); - } - - /** - * Returns a new TaskResult that, when this task completes - * normally, is executed using the supplied Scheduler, with this - * task's result as the argument to the supplied function. - * - * @param name the name of this new TaskResult for displaying - * @param scheduler the executor to use for asynchronous execution - * @param fn the function to use to compute the value of the returned TaskResult - * @param the function's return type - * @return the new TaskResult - */ - public TaskResult thenApply(String name, Scheduler scheduler, ExceptionalFunction fn) { - return new Subtask<>(name, scheduler, fn); - } - - /** - * Returns a new Task that, when this task completes - * normally, is executed using the default Scheduler, with this - * task's result as the argument to the supplied action. - * - * @param action the action to perform before completing the - * returned Task - * @return the new Task - */ - public Task thenAccept(ExceptionalConsumer action) { - return thenAccept(Schedulers.defaultScheduler(), action); - } - - /** - * Returns a new Task that, when this task completes - * normally, is executed using the supplied Scheduler, with this - * task's result as the argument to the supplied action. - * - * @param action the action to perform before completing the returned Task - * @param scheduler the executor to use for asynchronous execution - * @return the new Task - */ - public Task thenAccept(Scheduler scheduler, ExceptionalConsumer action) { - return new CoupleTask(this, () -> Task.of(scheduler, () -> action.accept(getResult())), true); - } - - /** - * Returns a new Task with the same exception as this task, that executes - * the given actions when this task completes. - * - *

When this task is complete, the given success action is invoked with - * the result, the given failure action is invoked with the exception of - * this task. The returned task is completed when the action returns. If - * the supplied action itself encounters an exception, then the returned - * task exceptionally completes with this exception unless this task also - * completed exceptionally. - * - * @param success the action to perform when this task successfully completed - * @param failure the action to perform when this task exceptionally returned - * @return the new Task - */ - public Task whenComplete(Scheduler scheduler, ExceptionalConsumer success, ExceptionalConsumer failure) { - return whenComplete(scheduler, () -> success.accept(getResult()), failure); - } - - /** - * Returns a new Task with the same exception as this task, that executes - * the given action when this task completes. - * - *

When this task is complete, the given action is invoked with the - * result (or {@code null} if none), a boolean value represents the - * execution status of this task, and the exception (or {@code null} - * if none) of this task as arguments. The returned task is completed - * when the action returns. If the supplied action itself encounters an - * exception, then the returned task exceptionally completes with this - * exception unless this task also completed exceptionally. - * - * @param action the action to perform - * @return the new Task - */ - public Task whenComplete(Scheduler scheduler, FinalizedCallback action) { - return whenComplete(scheduler, ((isDependentSucceeded, exception) -> action.execute(getResult(), isDependentSucceeded, exception))); - } - - private class Subtask extends TaskResult { - private final Scheduler scheduler; - private final ExceptionalFunction callable; - - public Subtask(String name, Scheduler scheduler, ExceptionalFunction callable) { - this.scheduler = scheduler; - this.callable = callable; - - setName(name); - } - - @Override - public Collection getDependents() { - return Collections.singleton(TaskResult.this); - } - - @Override - public Scheduler getScheduler() { - return scheduler; - } - - @Override - public void execute() throws Exception { - setResult(callable.apply(TaskResult.this.getResult())); - } - } - - public interface FinalizedCallback { - void execute(V result, boolean isDependentSucceeded, Exception exception) throws Exception; - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/function/ExceptionalRunnable.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/function/ExceptionalRunnable.java index 2ba87acb3..cfee8fcea 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/function/ExceptionalRunnable.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/function/ExceptionalRunnable.java @@ -27,15 +27,11 @@ public interface ExceptionalRunnable { void run() throws E; - default Callable toCallable() { + default Callable toCallable() { return () -> { run(); return null; }; } - static ExceptionalRunnable fromRunnable(Runnable r) { - return r::run; - } - } diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/TaskTest.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/TaskTest.java new file mode 100644 index 000000000..5520461bb --- /dev/null +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/TaskTest.java @@ -0,0 +1,18 @@ +package org.jackhuang.hmcl.util; + +import org.jackhuang.hmcl.task.Task; +import org.junit.Assert; +import org.junit.Test; + +public class TaskTest { + @Test + public void testWhenComplete() { + Task.composeAsync(() -> Task.allOf( + Task.allOf(Task.runAsync(() -> { + throw new Exception(); + })) + )).whenComplete(((isDependentSucceeded, exception) -> { + Assert.assertFalse(isDependentSucceeded); + })).test(); + } +}