Browse Source

"lock" deduplication

Sebastian Stenzel 5 years ago
parent
commit
f95b2baad5

+ 118 - 0
main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java

@@ -0,0 +1,118 @@
+package org.cryptomator.ui.common;
+
+import javafx.application.Platform;
+import javafx.concurrent.ScheduledService;
+import javafx.concurrent.Service;
+import javafx.concurrent.Task;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.common.vaults.Volume;
+import org.cryptomator.ui.fxapp.FxApplicationScoped;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.ExecutorService;
+
+@FxApplicationScoped
+public class VaultService {
+
+	private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
+
+	private final ExecutorService executorService;
+
+	@Inject
+	public VaultService(ExecutorService executorService) {
+		this.executorService = executorService;
+	}
+
+	/**
+	 * Locks a vault in a background thread.
+	 *
+	 * @param vault The vault to lock
+	 * @param forced Whether to attempt a forced lock
+	 */
+	public void lock(Vault vault, boolean forced) {
+		Task<Void> task = createLockTask(vault, forced);
+		task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayableName()));
+		task.setOnFailed(evt -> LOG.error("Failed to lock vault " + vault.getDisplayableName(), evt.getSource().getException()));
+		executorService.execute(task);
+	}
+
+	public void lockAll(Collection<Vault> vaults, boolean forced) {
+		Service<Void> service = createLockAllService(vaults, forced);
+		service.setOnFailed(evt -> LOG.error("Failed to lock vault", evt.getSource().getException()));
+		service.setExecutor(executorService);
+		service.start();
+	}
+
+	/**
+	 * Creates but doesn't start a lock-all service that can be run on a background thread.
+	 *
+	 * @param vaults The list of vaults to be locked. Must not be concurrently modified
+	 * @param forced Whether to attempt a forced lock
+	 * @return Service that tries to lock all given vaults
+	 */
+	public Service<Void> createLockAllService(Collection<Vault> vaults, boolean forced) {
+		Iterator<Vault> iter = vaults.iterator();
+		return new ScheduledService<>() {
+
+			@Override
+			protected Task<Void> createTask() {
+				assert Platform.isFxApplicationThread();
+				if (iter.hasNext()) {
+					return createLockTask(iter.next(), forced);
+				} else {
+					// This should be unreachable code, since iter is only accessed on the FX App Thread.
+					// But if quitting the application takes longer for any reason, this service should shut down properly
+					reset();
+					return createNoopTask();
+				}
+			}
+		};
+	}
+
+	/**
+	 * Creates but doesn't start a lock task that can be run on a background thread.
+	 *
+	 * @param vault The vault to lock
+	 * @param forced Whether to attempt a forced lock
+	 * @return Task that tries to lock the given vault
+	 */
+	public Task<Void> createLockTask(Vault vault, boolean forced) {
+		return new Task<>() {
+			@Override
+			protected Void call() throws Volume.VolumeException {
+				vault.lock(forced);
+				return null;
+			}
+
+			@Override
+			protected void scheduled() {
+				vault.setState(VaultState.PROCESSING);
+			}
+
+			@Override
+			protected void succeeded() {
+				vault.setState(VaultState.LOCKED);
+			}
+
+			@Override
+			protected void failed() {
+				vault.setState(VaultState.UNLOCKED);
+			}
+		};
+	}
+
+	private Task<Void> createNoopTask() {
+		return new Task<>() {
+			@Override
+			protected Void call() {
+				return null;
+			}
+		};
+	}
+
+}

+ 6 - 15
main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java

@@ -8,6 +8,7 @@ import org.cryptomator.common.vaults.VaultState;
 import org.cryptomator.common.vaults.Volume;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.Tasks;
+import org.cryptomator.ui.common.VaultService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -20,12 +21,12 @@ public class VaultDetailUnlockedController implements FxController {
 	private static final Logger LOG = LoggerFactory.getLogger(VaultDetailUnlockedController.class);
 
 	private final ReadOnlyObjectProperty<Vault> vault;
-	private final ExecutorService executor;
+	private final VaultService vaultService;
 
 	@Inject
-	public VaultDetailUnlockedController(ObjectProperty<Vault> vault, ExecutorService executor) {
+	public VaultDetailUnlockedController(ObjectProperty<Vault> vault, VaultService vaultService) {
 		this.vault = vault;
-		this.executor = executor;
+		this.vaultService = vaultService;
 	}
 
 	@FXML
@@ -39,18 +40,8 @@ public class VaultDetailUnlockedController implements FxController {
 
 	@FXML
 	public void lock() {
-		Vault v = vault.get();
-		v.setState(VaultState.PROCESSING);
-		Tasks.create(() -> {
-			v.lock(false);
-		}).onSuccess(() -> {
-			LOG.trace("Regular unmount succeeded.");
-			v.setState(VaultState.LOCKED);
-		}).onError(Exception.class, e -> {
-			v.setState(VaultState.UNLOCKED);
-			LOG.error("Regular unmount failed.", e);
-			// TODO
-		}).runOnce(executor);
+		vaultService.lock(vault.get(), false);
+		// TODO count lock attempts, and allow forced lock
 	}
 
 	/* Getter/Setter */

+ 9 - 72
main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java

@@ -1,17 +1,14 @@
 package org.cryptomator.ui.quit;
 
-import javafx.application.Platform;
 import javafx.collections.ObservableList;
-import javafx.concurrent.ScheduledService;
-import javafx.concurrent.Task;
+import javafx.concurrent.Service;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
 import javafx.scene.control.ContentDisplay;
 import javafx.stage.Stage;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultState;
-import org.cryptomator.common.vaults.Volume;
 import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.VaultService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -19,7 +16,6 @@ import javax.inject.Inject;
 import java.awt.desktop.QuitResponse;
 import java.util.Iterator;
 import java.util.List;
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 
 @QuitScoped
@@ -31,14 +27,16 @@ public class QuitController implements FxController {
 	private final QuitResponse response;
 	private final ObservableList<Vault> unlockedVaults;
 	private final ExecutorService executor;
+	private final VaultService vaultService;
 	public Button lockAndQuitButton;
 
 	@Inject
-	QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList<Vault> vaults, ExecutorService executor) {
+	QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList<Vault> vaults, ExecutorService executor, VaultService vaultService) {
 		this.window = window;
 		this.response = response;
 		this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
 		this.executor = executor;
+		this.vaultService = vaultService;
 	}
 
 	@FXML
@@ -52,11 +50,11 @@ public class QuitController implements FxController {
 	public void lockAndQuit() {
 		lockAndQuitButton.setDisable(true);
 		lockAndQuitButton.setContentDisplay(ContentDisplay.LEFT);
-		
-		Iterator<Vault> toBeLocked = List.copyOf(unlockedVaults).iterator();
-		ScheduledService<Void> lockAllService = new LockAllVaultsService(executor, toBeLocked);
+
+		Service<Void> lockAllService = vaultService.createLockAllService(List.copyOf(unlockedVaults), false);
+
 		lockAllService.setOnSucceeded(evt -> {
-			if (!toBeLocked.hasNext()) {
+			if (unlockedVaults.isEmpty()) {
 				window.close();
 				response.performQuit();
 			}
@@ -71,65 +69,4 @@ public class QuitController implements FxController {
 		lockAllService.start();
 	}
 
-	/**
-	 * @param vault The vault to lock
-	 * @return Task that tries to lock the given vault gracefully.
-	 */
-	private Task<Void> createGracefulLockTask(Vault vault) {
-		Task task = new Task<Void>() {
-			@Override
-			protected Void call() throws Volume.VolumeException {
-				vault.lock(false);
-				LOG.info("Locked {}", vault.getDisplayableName());
-				return null;
-			}
-		};
-		task.setOnScheduled(evt -> {
-			vault.setState(VaultState.PROCESSING);
-		});
-		task.setOnSucceeded(evt -> {
-			vault.setState(VaultState.LOCKED);
-		});
-		task.setOnFailed(evt -> {
-			LOG.warn("Failed to lock vault", vault);
-		});
-		return task;
-	}
-
-	/**
-	 * @return Task that succeeds immediately
-	 */
-	private Task<Void> createNoopTask() {
-		return new Task<>() {
-			@Override
-			protected Void call() {
-				return null;
-			}
-		};
-	}
-	
-	private class LockAllVaultsService extends ScheduledService<Void> {
-
-		private final Iterator<Vault> vaultsToLock;
-
-		public LockAllVaultsService(Executor executor, Iterator<Vault> vaultsToLock) {
-			this.vaultsToLock = vaultsToLock;
-			setExecutor(executor);
-			setRestartOnFailure(false);
-		}
-
-		@Override
-		protected Task<Void> createTask() {
-			assert Platform.isFxApplicationThread();
-			if (vaultsToLock.hasNext()) {
-				return createGracefulLockTask(vaultsToLock.next());
-			} else {
-				// This should be unreachable code, since vaultsToLock is only accessed on the FX App Thread.
-				// But if quitting the application takes longer for any reason, this service should shut down properly
-				reset();
-				return createNoopTask();
-			}
-		}
-	}
-	
 }