Sebastian Stenzel 8 年之前
父节点
当前提交
0906abdea9

+ 13 - 0
main/commons/src/main/java/org/cryptomator/common/Optionals.java

@@ -1,6 +1,7 @@
 package org.cryptomator.common;
 
 import java.util.Optional;
+import java.util.function.Function;
 
 public final class Optionals {
 
@@ -14,4 +15,16 @@ public final class Optionals {
 		}
 	}
 
+	/**
+	 * Returns a function that is equivalent to the input function but immediately gets the value of the returned optional when invoked.
+	 * 
+	 * @param <T> the type of the input to the function
+	 * @param <R> the type of the result of the function
+	 * @param optionalFunction An input function {@code Function<Foo, Optional<Bar>>}
+	 * @return A {@code Function<Foo, Bar>}, that may throw an NoSuchElementException, if the original function returns an empty optional.
+	 */
+	public static <T, R> Function<T, R> unwrap(Function<T, Optional<R>> optionalFunction) {
+		return t -> optionalFunction.apply(t).get();
+	}
+
 }

+ 1 - 9
main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java

@@ -62,15 +62,7 @@ public class ExitUtil {
 		this.macFunctions = macFunctions;
 	}
 
-	public void initExitHandler() {
-		initExitHandler(ExitUtil::platformExitOnMainThread);
-	}
-
-	private static void platformExitOnMainThread() {
-		Platform.runLater(Platform::exit);
-	}
-
-	private void initExitHandler(Runnable exitCommand) {
+	public void initExitHandler(Runnable exitCommand) {
 		if (SystemUtils.IS_OS_LINUX) {
 			initMinimizeExitHandler(exitCommand);
 		} else {

+ 6 - 1
main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java

@@ -189,10 +189,15 @@ public class MainController implements ViewController {
 			stage.getIcons().add(new Image(getClass().getResourceAsStream("/window_icon.png")));
 			Application.setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString());
 		}
-		exitUtil.initExitHandler();
+		exitUtil.initExitHandler(this::gracefulShutdown);
 		listenToFileOpenRequests(stage);
 	}
 
+	private void gracefulShutdown() {
+		vaults.filtered(Vault::isUnlocked).forEach(Vault::prepareForShutdown);
+		Platform.runLater(Platform::exit);
+	}
+
 	private void loadFont(String resourcePath) {
 		try (InputStream in = getClass().getResourceAsStream(resourcePath)) {
 			Font.loadFont(in, 12.0);

+ 33 - 7
main/ui/src/main/java/org/cryptomator/ui/model/Vault.java

@@ -18,13 +18,14 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 
 import javax.inject.Inject;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.common.ConsumerThrowingException;
 import org.cryptomator.common.LazyInitializer;
+import org.cryptomator.common.Optionals;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.cryptofs.CryptoFileSystem;
@@ -36,6 +37,7 @@ import org.cryptomator.frontend.webdav.WebDavServer;
 import org.cryptomator.frontend.webdav.mount.MountParams;
 import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
 import org.cryptomator.frontend.webdav.mount.Mounter.Mount;
+import org.cryptomator.frontend.webdav.mount.Mounter.UnmountOperation;
 import org.cryptomator.frontend.webdav.servlet.WebDavServletController;
 import org.cryptomator.ui.model.VaultModule.PerVault;
 import org.cryptomator.ui.util.DeferredCloser;
@@ -143,17 +145,17 @@ public class Vault {
 		});
 	}
 
-	public synchronized void unmount() throws Exception {
-		unmount(mount -> mount.unmount());
+	public synchronized void unmount() throws CommandFailedException {
+		unmount(Function.identity());
 	}
 
-	public synchronized void unmountForced() throws Exception {
-		unmount(mount -> mount.forced().get().unmount());
+	public synchronized void unmountForced() throws CommandFailedException {
+		unmount(Optionals.unwrap(Mount::forced));
 	}
 
-	private synchronized void unmount(ConsumerThrowingException<Mount, CommandFailedException> command) throws CommandFailedException {
+	private synchronized void unmount(Function<Mount, ? extends UnmountOperation> unmountOperationChooser) throws CommandFailedException {
 		if (mount != null) {
-			command.accept(mount);
+			unmountOperationChooser.apply(mount).unmount();
 		}
 		Platform.runLater(() -> {
 			mounted.set(false);
@@ -177,6 +179,30 @@ public class Vault {
 		});
 	}
 
+	/**
+	 * Ejects any mounted drives and locks this vault. no-op if this vault is currently locked.
+	 */
+	public void prepareForShutdown() {
+		try {
+			unmount();
+		} catch (CommandFailedException e) {
+			if (supportsForcedUnmount()) {
+				try {
+					unmountForced();
+				} catch (CommandFailedException e1) {
+					LOG.warn("Failed to force unmount vault.");
+				}
+			} else {
+				LOG.warn("Failed to gracefully unmount vault.");
+			}
+		}
+		try {
+			lock();
+		} catch (Exception e) {
+			LOG.warn("Failed to lock vault.");
+		}
+	}
+
 	public void reveal() throws CommandFailedException {
 		if (mount != null) {
 			mount.reveal();