From 30dc8eecb1fafbe101f06dcea0a13c78f8d576db Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sun, 22 Feb 2015 13:21:08 +0100 Subject: [PATCH] - Refactored WebDavMounter (using Guice) - implemented warm start for windows mounts --- .../org/cryptomator/ui/MainController.java | 11 ++--- .../java/org/cryptomator/ui/MainModule.java | 9 ++++ .../java/org/cryptomator/ui/model/Vault.java | 13 +++-- .../cryptomator/ui/model/VaultFactory.java | 25 ++++++++++ .../ui/model/VaultObjectMapperProvider.java | 14 +++--- .../ui/util/mount/FallbackWebDavMounter.java | 5 ++ .../ui/util/mount/LinuxGvfsWebDavMounter.java | 5 ++ .../ui/util/mount/MacOsXWebDavMounter.java | 5 ++ .../ui/util/mount/WebDavMounter.java | 36 +------------- .../ui/util/mount/WebDavMounterProvider.java | 47 +++++++++++++++++++ .../ui/util/mount/WebDavMounterStrategy.java | 14 ++---- .../ui/util/mount/WindowsWebDavMounter.java | 10 ++++ 12 files changed, 132 insertions(+), 62 deletions(-) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterProvider.java diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/MainController.java index 78deb7b4f..421fcf60f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainController.java @@ -38,19 +38,18 @@ import javafx.stage.FileChooser; import javafx.stage.Stage; import javafx.stage.WindowEvent; -import org.cryptomator.crypto.Cryptor; import org.cryptomator.ui.InitializeController.InitializationListener; import org.cryptomator.ui.MainModule.ControllerFactory; import org.cryptomator.ui.UnlockController.UnlockListener; import org.cryptomator.ui.UnlockedController.LockListener; import org.cryptomator.ui.controls.DirectoryListCell; import org.cryptomator.ui.model.Vault; +import org.cryptomator.ui.model.VaultFactory; import org.cryptomator.ui.settings.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; -import com.google.inject.Provider; public class MainController implements Initializable, InitializationListener, UnlockListener, LockListener { @@ -78,16 +77,16 @@ public class MainController implements Initializable, InitializationListener, Un private final ControllerFactory controllerFactory; private final Settings settings; - private final Provider cryptorProvider; + private final VaultFactory vaultFactoy; private ResourceBundle rb; @Inject - public MainController(ControllerFactory controllerFactory, Settings settings, Provider cryptorProvider) { + public MainController(ControllerFactory controllerFactory, Settings settings, VaultFactory vaultFactoy) { super(); this.controllerFactory = controllerFactory; this.settings = settings; - this.cryptorProvider = cryptorProvider; + this.vaultFactoy = vaultFactoy; } @Override @@ -167,7 +166,7 @@ public class MainController implements Initializable, InitializationListener, Un return; } - final Vault vault = new Vault(vaultPath, cryptorProvider.get()); + final Vault vault = vaultFactoy.createVault(vaultPath); if (!directoryList.getItems().contains(vault)) { directoryList.getItems().add(vault); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainModule.java b/main/ui/src/main/java/org/cryptomator/ui/MainModule.java index 14520604d..3db7e07f4 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainModule.java @@ -18,11 +18,14 @@ import javax.inject.Singleton; import org.cryptomator.crypto.Cryptor; import org.cryptomator.crypto.SamplingDecorator; import org.cryptomator.crypto.aes256.Aes256Cryptor; +import org.cryptomator.ui.model.VaultFactory; import org.cryptomator.ui.model.VaultObjectMapperProvider; import org.cryptomator.ui.settings.Settings; import org.cryptomator.ui.settings.SettingsProvider; import org.cryptomator.ui.util.DeferredCloser; import org.cryptomator.ui.util.DeferredCloser.Closer; +import org.cryptomator.ui.util.mount.WebDavMounter; +import org.cryptomator.ui.util.mount.WebDavMounterProvider; import org.cryptomator.webdav.WebDavServer; import com.fasterxml.jackson.databind.ObjectMapper; @@ -44,6 +47,7 @@ public class MainModule extends AbstractModule { bind(DeferredCloser.class).toInstance(deferredCloser); bind(ObjectMapper.class).annotatedWith(Names.named("VaultJsonMapper")).toProvider(VaultObjectMapperProvider.class); bind(Settings.class).toProvider(SettingsProvider.class); + bind(WebDavMounter.class).toProvider(WebDavMounterProvider.class).asEagerSingleton(); } @Provides @@ -63,6 +67,11 @@ public class MainModule extends AbstractModule { return SamplingDecorator.decorate(new Aes256Cryptor()); } + @Provides + VaultFactory getVaultFactory(Cryptor cryptor, WebDavMounter mounter) { + return new VaultFactory(cryptor, mounter); + } + @Provides @Singleton WebDavServer getServer() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 98867d0ee..bc4caefdc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -31,19 +31,24 @@ public class Vault implements Serializable { public static final String VAULT_FILE_EXTENSION = ".cryptomator"; - private final Cryptor cryptor; - private final ObjectProperty unlocked = new SimpleObjectProperty(this, "unlocked", Boolean.FALSE); private final Path path; + private final Cryptor cryptor; + private final WebDavMounter mounter; + private final ObjectProperty unlocked = new SimpleObjectProperty(this, "unlocked", Boolean.FALSE); private String mountName; private DeferredClosable webDavServlet = DeferredClosable.empty(); private DeferredClosable webDavMount = DeferredClosable.empty(); - public Vault(final Path vaultDirectoryPath, final Cryptor cryptor) { + /** + * Package private constructor, use {@link VaultFactory}. + */ + Vault(final Path vaultDirectoryPath, final Cryptor cryptor, final WebDavMounter mounter) { if (!Files.isDirectory(vaultDirectoryPath) || !vaultDirectoryPath.getFileName().toString().endsWith(VAULT_FILE_EXTENSION)) { throw new IllegalArgumentException("Not a valid vault directory: " + vaultDirectoryPath); } this.path = vaultDirectoryPath; this.cryptor = cryptor; + this.mounter = mounter; try { setMountName(getName()); @@ -81,7 +86,7 @@ public class Vault implements Serializable { return false; } try { - webDavMount = closer.closeLater(WebDavMounter.mount(o.get().getServletUri(), getMountName()), WebDavMount::unmount); + webDavMount = closer.closeLater(mounter.mount(o.get().getServletUri(), getMountName()), WebDavMount::unmount); return true; } catch (CommandFailedException e) { LOG.warn("mount failed", e); diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java b/main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java new file mode 100644 index 000000000..7deb37a94 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java @@ -0,0 +1,25 @@ +package org.cryptomator.ui.model; + +import java.nio.file.Path; + +import org.cryptomator.crypto.Cryptor; +import org.cryptomator.ui.util.mount.WebDavMounter; + +import com.google.inject.Inject; + +public class VaultFactory { + + private final Cryptor cryptor; + private final WebDavMounter mounter; + + @Inject + public VaultFactory(Cryptor cryptor, WebDavMounter mounter) { + this.cryptor = cryptor; + this.mounter = mounter; + } + + public Vault createVault(Path path) { + return new Vault(path, cryptor, mounter); + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/VaultObjectMapperProvider.java b/main/ui/src/main/java/org/cryptomator/ui/model/VaultObjectMapperProvider.java index 7cac1a904..9c35838f2 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/VaultObjectMapperProvider.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/VaultObjectMapperProvider.java @@ -6,8 +6,6 @@ import java.nio.file.Path; import javax.inject.Inject; -import org.cryptomator.crypto.Cryptor; - import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; @@ -22,11 +20,11 @@ import com.google.inject.Provider; public class VaultObjectMapperProvider implements Provider { - private final Provider cryptorProvider; + private final VaultFactory vaultFactoy; @Inject - public VaultObjectMapperProvider(final Provider cryptorProvider) { - this.cryptorProvider = cryptorProvider; + public VaultObjectMapperProvider(final VaultFactory vaultFactoy) { + this.vaultFactoy = vaultFactoy; } @Override @@ -58,11 +56,11 @@ public class VaultObjectMapperProvider implements Provider { final JsonNode node = jp.readValueAsTree(); final String pathStr = node.get("path").asText(); final Path path = FileSystems.getDefault().getPath(pathStr); - final Vault dir = new Vault(path, cryptorProvider.get()); + final Vault vault = vaultFactoy.createVault(path); if (node.has("mountName")) { - dir.setMountName(node.get("mountName").asText()); + vault.setMountName(node.get("mountName").asText()); } - return dir; + return vault; } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/FallbackWebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/FallbackWebDavMounter.java index 2cf46d083..c3168ec06 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/FallbackWebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/FallbackWebDavMounter.java @@ -22,6 +22,11 @@ final class FallbackWebDavMounter implements WebDavMounterStrategy { return true; } + @Override + public void warmUp(int serverPort) { + // no-op + } + @Override public WebDavMount mount(URI uri, String name) { displayMountInstructions(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/LinuxGvfsWebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/LinuxGvfsWebDavMounter.java index bd6feec29..f8a78e6ba 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/LinuxGvfsWebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/LinuxGvfsWebDavMounter.java @@ -30,6 +30,11 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy { return false; } } + + @Override + public void warmUp(int serverPort) { + // no-op + } @Override public WebDavMount mount(URI uri, String name) throws CommandFailedException { diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/MacOsXWebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/MacOsXWebDavMounter.java index 12100fa6b..92587f906 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/MacOsXWebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/MacOsXWebDavMounter.java @@ -21,6 +21,11 @@ final class MacOsXWebDavMounter implements WebDavMounterStrategy { return SystemUtils.IS_OS_MAC_OSX; } + @Override + public void warmUp(int serverPort) { + // no-op + } + @Override public WebDavMount mount(URI uri, String name) throws CommandFailedException { final String path = "/Volumes/Cryptomator" + uri.getRawPath().replace('/', '_'); diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounter.java index 793863399..7c7a5b2b6 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounter.java @@ -11,16 +11,7 @@ package org.cryptomator.ui.util.mount; import java.net.URI; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class WebDavMounter { - - private static final Logger LOG = LoggerFactory.getLogger(WebDavMounter.class); - - private static final WebDavMounterStrategy[] STRATEGIES = {new WindowsWebDavMounter(), new MacOsXWebDavMounter(), new LinuxGvfsWebDavMounter()}; - - private static volatile WebDavMounterStrategy choosenStrategy; +public interface WebDavMounter { /** * Tries to mount a given webdav share. @@ -30,29 +21,6 @@ public final class WebDavMounter { * @return a {@link WebDavMount} representing the mounted share * @throws CommandFailedException if the mount operation fails */ - public static WebDavMount mount(URI uri, String name) throws CommandFailedException { - return chooseStrategy().mount(uri, name); - } - - private static WebDavMounterStrategy chooseStrategy() { - if (choosenStrategy == null) { - choosenStrategy = getStrategyWhichShouldWork(); - } - return choosenStrategy; - } - - private static WebDavMounterStrategy getStrategyWhichShouldWork() { - for (WebDavMounterStrategy strategy : STRATEGIES) { - if (strategy.shouldWork()) { - LOG.info("Using {}", strategy.getClass().getSimpleName()); - return strategy; - } - } - return new FallbackWebDavMounter(); - } - - private WebDavMounter() { - throw new IllegalStateException("Class is not instantiable."); - } + WebDavMount mount(URI uri, String name) throws CommandFailedException; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterProvider.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterProvider.java new file mode 100644 index 000000000..8e6ca6f4f --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterProvider.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2014 Sebastian Stenzel + * This file is licensed under the terms of the MIT license. + * See the LICENSE.txt file for more info. + * + * Contributors: + * Markus Kreusch - Refactored to use strategy pattern + * Sebastian Stenzel - Refactored to use Guice provider, added warmup-phase for windows mounts. + ******************************************************************************/ +package org.cryptomator.ui.util.mount; + +import javax.inject.Inject; + +import org.cryptomator.webdav.WebDavServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Provider; + +public class WebDavMounterProvider implements Provider { + + private static final Logger LOG = LoggerFactory.getLogger(WebDavMounterProvider.class); + private static final WebDavMounterStrategy[] STRATEGIES = {new WindowsWebDavMounter(), new MacOsXWebDavMounter(), new LinuxGvfsWebDavMounter()}; + private final WebDavMounterStrategy choosenStrategy; + + @Inject + public WebDavMounterProvider(WebDavServer server) { + this.choosenStrategy = getStrategyWhichShouldWork(); + this.choosenStrategy.warmUp(server.getPort()); + } + + @Override + public WebDavMounterStrategy get() { + return this.choosenStrategy; + } + + private static WebDavMounterStrategy getStrategyWhichShouldWork() { + for (WebDavMounterStrategy strategy : STRATEGIES) { + if (strategy.shouldWork()) { + LOG.info("Using {}", strategy.getClass().getSimpleName()); + return strategy; + } + } + return new FallbackWebDavMounter(); + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterStrategy.java index e970e154d..deff797ee 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WebDavMounterStrategy.java @@ -9,14 +9,12 @@ ******************************************************************************/ package org.cryptomator.ui.util.mount; -import java.net.URI; - /** * A strategy able to mount a webdav share and display it to the user. * * @author Markus Kreusch */ -interface WebDavMounterStrategy { +interface WebDavMounterStrategy extends WebDavMounter { /** * @return {@code false} if this {@code WebDavMounterStrategy} can not work on the local machine, {@code true} if it could work @@ -24,13 +22,9 @@ interface WebDavMounterStrategy { boolean shouldWork(); /** - * Tries to mount a given webdav share. - * - * @param uri URI of the webdav share - * @param name the name under which the folder is to be mounted. This might be ignored. - * @return a {@link WebDavMount} representing the mounted share - * @throws CommandFailedException if the mount operation fails + * Invoked when mounting strategy gets chosen. On some operating systems (we don't want to tell names here) mounting might be faster, + * when certain things are prepared before the actual mount attempt. */ - WebDavMount mount(URI uri, String name) throws CommandFailedException; + void warmUp(int serverPort); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java index 46af465c7..d5ab03aa5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java @@ -36,6 +36,16 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy { return SystemUtils.IS_OS_WINDOWS; } + @Override + public void warmUp(int serverPort) { + final URI warmUpUri = URI.create("http://0--1.ipv6-literal.net:" + serverPort + "/bill-gates-mom-uses-goto"); + try { + this.mount(warmUpUri, "WarmUpMount"); + } catch (CommandFailedException e) { + // will most certainly throw an exception, because this is a fake WebDav path. But now windows has some DNS things cached :) + } + } + @Override public WebDavMount mount(URI uri, String name) throws CommandFailedException { final Script mountScript = fromLines("net use * http://0--1.ipv6-literal.net:%PORT%%DAV_PATH% /persistent:no")