Ver código fonte

replaced UserInteractionLock with CompletableFuture in LockWorkflow

Sebastian Stenzel 3 anos atrás
pai
commit
9856792921

+ 0 - 61
src/main/java/org/cryptomator/ui/common/UserInteractionLock.java

@@ -1,61 +0,0 @@
-package org.cryptomator.ui.common;
-
-import javafx.application.Platform;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.ReadOnlyBooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class UserInteractionLock<E extends Enum<E>> {
-
-	private final Lock lock = new ReentrantLock();
-	private final Condition condition = lock.newCondition();
-	private final BooleanProperty awaitingInteraction = new SimpleBooleanProperty();
-	private final AtomicBoolean interacted = new AtomicBoolean();
-	private final AtomicReference<E> state;
-
-	public UserInteractionLock(E initialValue) {
-		this.state = new AtomicReference<>(initialValue);
-	}
-
-	public synchronized void reset(E value) {
-		state.set(value);
-		interacted.set(false);
-	}
-
-	public void interacted(E result) {
-		assert Platform.isFxApplicationThread();
-		lock.lock();
-		try {
-			state.set(result);
-			interacted.set(true);
-			awaitingInteraction.set(false);
-			condition.signal();
-		} finally {
-			lock.unlock();
-		}
-	}
-
-	public E awaitInteraction() throws InterruptedException {
-		assert !Platform.isFxApplicationThread();
-		lock.lock();
-		try {
-			Platform.runLater(() -> awaitingInteraction.set(true));
-			while (!interacted.get()) {
-				condition.await();
-			}
-			return state.get();
-		} finally {
-			lock.unlock();
-		}
-	}
-
-	public ReadOnlyBooleanProperty awaitingInteraction() {
-		return awaitingInteraction;
-	}
-
-}

+ 8 - 12
src/main/java/org/cryptomator/ui/lock/LockForcedController.java

@@ -2,7 +2,6 @@ package org.cryptomator.ui.lock;
 
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.common.UserInteractionLock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -10,6 +9,8 @@ import javax.inject.Inject;
 import javafx.fxml.FXML;
 import javafx.stage.Stage;
 import javafx.stage.WindowEvent;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
 
 @LockScoped
 public class LockForcedController implements FxController {
@@ -18,40 +19,35 @@ public class LockForcedController implements FxController {
 
 	private final Stage window;
 	private final Vault vault;
-	private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
+	private final AtomicReference<CompletableFuture<Boolean>> forceRetryDecision;
 
 	@Inject
-	public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock) {
+	public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, AtomicReference<CompletableFuture<Boolean>> forceRetryDecision) {
 		this.window = window;
 		this.vault = vault;
-		this.forceLockDecisionLock = forceLockDecisionLock;
+		this.forceRetryDecision = forceRetryDecision;
 		this.window.setOnHiding(this::windowClosed);
 	}
 
 	@FXML
 	public void cancel() {
-		forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
 		window.close();
 	}
 
 	@FXML
 	public void retry() {
-		forceLockDecisionLock.interacted(LockModule.ForceLockDecision.RETRY);
+		forceRetryDecision.get().complete(false);
 		window.close();
 	}
 
 	@FXML
 	public void force() {
-		forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE);
+		forceRetryDecision.get().complete(true);
 		window.close();
 	}
 
 	private void windowClosed(WindowEvent windowEvent) {
-		// if not already interacted, set the decision to CANCEL
-		if (forceLockDecisionLock.awaitingInteraction().get()) {
-			LOG.debug("Lock canceled in force-lock-phase by user.");
-			forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
-		}
+		forceRetryDecision.get().cancel(true);
 	}
 
 	// ----- Getter & Setter -----

+ 5 - 10
src/main/java/org/cryptomator/ui/lock/LockModule.java

@@ -6,13 +6,12 @@ import dagger.Provides;
 import dagger.multibindings.IntoMap;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.ui.common.DefaultSceneFactory;
-import org.cryptomator.ui.common.FxmlLoaderFactory;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.FxControllerKey;
 import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlLoaderFactory;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.StageFactory;
-import org.cryptomator.ui.common.UserInteractionLock;
 
 import javax.inject.Named;
 import javax.inject.Provider;
@@ -22,20 +21,16 @@ import javafx.stage.Stage;
 import java.util.Map;
 import java.util.Optional;
 import java.util.ResourceBundle;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
 
 @Module
 abstract class LockModule {
 
-	enum ForceLockDecision {
-		CANCEL,
-		RETRY,
-		FORCE;
-	}
-
 	@Provides
 	@LockScoped
-	static UserInteractionLock<LockModule.ForceLockDecision> provideForceLockDecisionLock() {
-		return new UserInteractionLock<>(null);
+	static AtomicReference<CompletableFuture<Boolean>> provideForceRetryDecisionRef() {
+		return new AtomicReference<>();
 	}
 
 	@Provides

+ 23 - 16
src/main/java/org/cryptomator/ui/lock/LockWorkflow.java

@@ -8,7 +8,6 @@ import org.cryptomator.common.vaults.Volume;
 import org.cryptomator.ui.common.ErrorComponent;
 import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
-import org.cryptomator.ui.common.UserInteractionLock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -18,6 +17,10 @@ import javafx.concurrent.Task;
 import javafx.scene.Scene;
 import javafx.stage.Stage;
 import javafx.stage.Window;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * The sequence of actions performed and checked during lock of a vault.
@@ -34,43 +37,48 @@ public class LockWorkflow extends Task<Void> {
 
 	private final Stage lockWindow;
 	private final Vault vault;
-	private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
+	private final AtomicReference<CompletableFuture<Boolean>> forceRetryDecision;
 	private final Lazy<Scene> lockForcedScene;
 	private final Lazy<Scene> lockFailedScene;
 	private final ErrorComponent.Builder errorComponent;
 
 	@Inject
-	public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy<Scene> lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy<Scene> lockFailedScene, ErrorComponent.Builder errorComponent) {
+	public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, AtomicReference<CompletableFuture<Boolean>> forceRetryDecision, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy<Scene> lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy<Scene> lockFailedScene, ErrorComponent.Builder errorComponent) {
 		this.lockWindow = lockWindow;
 		this.vault = vault;
-		this.forceLockDecisionLock = forceLockDecisionLock;
+		this.forceRetryDecision = forceRetryDecision;
 		this.lockForcedScene = lockForcedScene;
 		this.lockFailedScene = lockFailedScene;
 		this.errorComponent = errorComponent;
 	}
 
 	@Override
-	protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException {
+	protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException, ExecutionException {
 		lock(false);
 		return null;
 	}
 
-	private void lock(boolean forced) throws InterruptedException {
+	private void lock(boolean forced) throws InterruptedException, ExecutionException {
 		try {
 			vault.lock(forced);
 		} catch (Volume.VolumeException | LockNotCompletedException e) {
 			LOG.info("Locking {} failed (forced: {}).", vault.getDisplayName(), forced, e);
-			var decision = askUserForAction();
-			switch (decision) {
-				case RETRY -> lock(false);
-				case FORCE -> lock(true);
-				case CANCEL -> cancel(false);
-			}
+			retryOrCancel();
+		}
+	}
+
+	private void retryOrCancel() throws ExecutionException, InterruptedException {
+		try {
+			boolean forced = askWhetherToUseTheForce().get();
+			lock(forced);
+		} catch (CancellationException e) {
+			cancel(false);
 		}
 	}
 
-	private LockModule.ForceLockDecision askUserForAction() throws InterruptedException {
-		forceLockDecisionLock.reset(null);
+	private CompletableFuture<Boolean> askWhetherToUseTheForce() {
+		var decision = new CompletableFuture<Boolean>();
+		forceRetryDecision.set(decision);
 		// show forcedLock dialogue ...
 		Platform.runLater(() -> {
 			lockWindow.setScene(lockForcedScene.get());
@@ -83,8 +91,7 @@ public class LockWorkflow extends Task<Void> {
 				lockWindow.centerOnScreen();
 			}
 		});
-		// ... and wait for answer
-		return forceLockDecisionLock.awaitInteraction();
+		return decision;
 	}
 
 	@Override