diff --git a/.travis.yml b/.travis.yml index 83a72d52d..67ff14276 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,9 @@ cache: - $HOME/.m2 env: global: - - secure: "IfYURwZaDWuBDvyn47n0k1Zod/IQw1FF+CS5nnV08Q+NfC3vGGJMwV8m59XnbfwnWGxwvCaAbk4qP6s6+ijgZNKkvgfFMo3rfTok5zt43bIqgaFOANYV+OC/1c59gYD6ZUxhW5iNgMgU3qdsRtJuwSmfkVv/jKyLGfAbS4kN8BA=" #coverity - - secure: "lV9OwUbHMrMpLUH1CY+Z4puLDdFXytudyPlG1eGRsesdpuG6KM3uQVz6uAtf6lrU8DRbMM/T7ML+PmvQ4UoPPYLdLxESLLBat2qUPOIVBOhTSlCc7I0DmGy04CSvkeMy8dPaQC0ukgNiR7zwoNzfcpGRN/U9S8tziDruuHoZSrg=" #bintray + - secure: "IfYURwZaDWuBDvyn47n0k1Zod/IQw1FF+CS5nnV08Q+NfC3vGGJMwV8m59XnbfwnWGxwvCaAbk4qP6s6+ijgZNKkvgfFMo3rfTok5zt43bIqgaFOANYV+OC/1c59gYD6ZUxhW5iNgMgU3qdsRtJuwSmfkVv/jKyLGfAbS4kN8BA=" # COVERITY_SCAN_TOKEN + - secure: "lV9OwUbHMrMpLUH1CY+Z4puLDdFXytudyPlG1eGRsesdpuG6KM3uQVz6uAtf6lrU8DRbMM/T7ML+PmvQ4UoPPYLdLxESLLBat2qUPOIVBOhTSlCc7I0DmGy04CSvkeMy8dPaQC0ukgNiR7zwoNzfcpGRN/U9S8tziDruuHoZSrg=" # BINTRAY_API_KEY + - secure: "oWFgRTVP6lyTa7qVxlvkpm20MtVc3BtmsNXQJS6bfg2A0o/iCQMNx7OD59BaafCLGRKvCcJVESiC8FlSylVMS7CDSyYu0gg70NUiIuHp4NBM5inFWYCy/PdQsCTzr5uvNG+rMFQpMFRaCV0FrfM3tLondcVkhsHL68l93Xoexx4=" # CODACY_PROJECT_TOKEN addons: coverity_scan: project: @@ -19,24 +20,10 @@ addons: branch_pattern: release.* install: # "clean" needed until https://bugs.openjdk.java.net/browse/JDK-8067747 is resolved. -- mvn -fmain/pom.xml clean package -DskipTests dependency:go-offline -Ptest-coverage +- mvn -fmain/pom.xml clean package -DskipTests dependency:go-offline -Pcoverage - mvn -fmain/pom.xml clean package -DskipTests dependency:go-offline -Prelease script: -- mvn --update-snapshots -fmain/pom.xml -Ptest-coverage clean test jacoco:report-aggregate -after_success: -- "bash <(curl -s https://codecov.io/bash)" -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/7d429ab35361726e26f2 - on_success: change - on_failure: always - on_start: false - slack: - rooms: - secure: "lngJ/HEAFBbD5AdiO9avMqptKpZHdmEwOzS9FabZjkdFh7yAYueTk5RniPUvShjsKtThYm7cJ8AtDMDwc07NvPrzbMBRtUJGwuDT+7c7YFALGFJ1NYi+emkC9x1oafvmPgEYSE+tMKzNcwrHi3ytGgKdIotsKwaF35QNXYA9aMs=" - on_success: change - on_failure: always +- mvn --update-snapshots -fmain/pom.xml clean test jacoco:report verify -Pcoverage before_deploy: - mvn -fmain/pom.xml -Prelease clean package -DskipTests deploy: diff --git a/README.md b/README.md index fb45efcab..aa80a5205 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ [![Build Status](https://travis-ci.org/cryptomator/cryptomator.svg?branch=master)](https://travis-ci.org/cryptomator/cryptomator) [![Coverity Scan Build Status](https://scan.coverity.com/projects/cryptomator-cryptomator/badge.svg?flat=1)](https://scan.coverity.com/projects/cryptomator-cryptomator) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2a0adf3cec6a4143b91035d3924178f1)](https://www.codacy.com/app/cryptomator/cryptomator?utm_source=github.com&utm_medium=referral&utm_content=cryptomator/cryptomator&utm_campaign=Badge_Grade) -[![Coverage Status](https://coveralls.io/repos/github/cryptomator/cryptomator/badge.svg?branch=master)](https://coveralls.io/github/cryptomator/cryptomator?branch=master) -[![Join the chat at https://gitter.im/cryptomator/cryptomator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cryptomator/cryptomator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator) [![POEditor](https://img.shields.io/badge/POEditor-Help%20Translate-blue.svg?style=flat)](https://poeditor.com/join/project/bHwbvJmx0E) diff --git a/main/ant-kit/pom.xml b/main/ant-kit/pom.xml index 571ef1968..5ccabafdf 100644 --- a/main/ant-kit/pom.xml +++ b/main/ant-kit/pom.xml @@ -8,7 +8,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 ant-kit pom diff --git a/main/commons/pom.xml b/main/commons/pom.xml index 58cadb135..7442d7b7f 100644 --- a/main/commons/pom.xml +++ b/main/commons/pom.xml @@ -10,7 +10,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 commons Cryptomator Commons @@ -53,13 +53,4 @@ test - - - - - org.jacoco - jacoco-maven-plugin - - - diff --git a/main/commons/src/main/java/org/cryptomator/common/CachingSupplier.java b/main/commons/src/main/java/org/cryptomator/common/CachingSupplier.java deleted file mode 100644 index 717d63920..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/CachingSupplier.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.cryptomator.common; - -import java.util.function.Supplier; - -public class CachingSupplier implements Supplier { - - public static Supplier from(Supplier delegate) { - return new CachingSupplier<>(delegate); - } - - private Supplier delegate; - - private CachingSupplier(Supplier delegate) { - this.delegate = () -> { - T result = delegate.get(); - CachingSupplier.this.delegate = () -> result; - return result; - }; - } - - @Override - public T get() { - return delegate.get(); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/Holder.java b/main/commons/src/main/java/org/cryptomator/common/Holder.java deleted file mode 100644 index f147ea3e6..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/Holder.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.cryptomator.common; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class Holder implements Supplier, Consumer { - - private final V initial; - - private V value; - - public Holder(W initial) { - this.initial = initial; - reset(); - } - - public V get() { - return value; - } - - public void set(V value) { - this.value = value; - } - - public void reset() { - set(initial); - } - - @Override - public void accept(V value) { - set(value); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java b/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java index 4d166bbb3..de5d8abfd 100644 --- a/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java +++ b/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java @@ -4,6 +4,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.function.UnaryOperator; +import com.google.common.base.Throwables; + public final class LazyInitializer { private LazyInitializer() { @@ -41,11 +43,9 @@ public final class LazyInitializer { try { return reference.updateAndGet(invokeFactoryIfNull(factory)); } catch (InitializationException e) { - if (exceptionType.isInstance(e.getCause())) { - throw exceptionType.cast(e.getCause()); - } else { - throw e; - } + Throwables.throwIfUnchecked(e); + Throwables.throwIfInstanceOf(e.getCause(), exceptionType); + throw e; } } } @@ -55,9 +55,8 @@ public final class LazyInitializer { if (currentValue == null) { try { return factory.get(); - } catch (RuntimeException e) { - throw e; // don't catch unchecked exceptions } catch (Exception e) { + Throwables.throwIfUnchecked(e); // don't catch unchecked exceptions throw new InitializationException(e); } } else { diff --git a/main/commons/src/main/java/org/cryptomator/common/Optionals.java b/main/commons/src/main/java/org/cryptomator/common/Optionals.java index d7c510bea..a97eb122a 100644 --- a/main/commons/src/main/java/org/cryptomator/common/Optionals.java +++ b/main/commons/src/main/java/org/cryptomator/common/Optionals.java @@ -1,17 +1,23 @@ package org.cryptomator.common; import java.util.Optional; +import java.util.function.Function; public final class Optionals { private Optionals() { } - public static void ifPresent(Optional optional, ConsumerThrowingException consumer) throws E { - final T t = optional.orElse(null); - if (t != null) { - consumer.accept(t); - } + /** + * Returns a function that is equivalent to the input function but immediately gets the value of the returned optional when invoked. + * + * @param the type of the input to the function + * @param the type of the result of the function + * @param function An {@code Optional}-bearing input function {@code Function>} + * @return A {@code Function}, that may throw a NoSuchElementException, if the original function returns an empty optional. + */ + public static Function unwrap(Function> function) { + return t -> function.apply(t).get(); } } diff --git a/main/commons/src/main/java/org/cryptomator/common/StackTrace.java b/main/commons/src/main/java/org/cryptomator/common/StackTrace.java deleted file mode 100644 index 8d7b64c8a..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/StackTrace.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Markus Kreusch and others. - * This file is licensed under the terms of the MIT license. - * See the LICENSE.txt file for more info. - * - * Contributors: - * Markus Kreusch - initial implementation - *******************************************************************************/ -package org.cryptomator.common; - -import java.util.stream.Stream; - -/** - * Utility to print stack traces while analyzing issues. - * - * @author Markus Kreusch - */ -public class StackTrace { - - public static void print(String message) { - Thread thread = Thread.currentThread(); - System.err.println(stackTraceFor(message, thread)); - } - - private static String stackTraceFor(String message, Thread thread) { - StringBuilder result = new StringBuilder(); - appendMessageAndThreadName(result, message, thread); - appendStackTrace(thread, result); - return result.toString(); - } - - private static void appendStackTrace(Thread thread, StringBuilder result) { - Stream.of(thread.getStackTrace()) // - .skip(4) // - .forEach(stackTraceElement -> append(stackTraceElement, result)); - } - - private static void appendMessageAndThreadName(StringBuilder result, String message, Thread thread) { - result // - .append('[') // - .append(thread.getName()) // - .append("] ") // - .append(message); - } - - private static void append(StackTraceElement stackTraceElement, StringBuilder result) { - String className = stackTraceElement.getClassName(); - String methodName = stackTraceElement.getMethodName(); - String fileName = stackTraceElement.getFileName(); - int lineNumber = stackTraceElement.getLineNumber(); - result.append('\n') // - .append(className).append(':').append(methodName) // - .append(" (").append(fileName).append(':').append(lineNumber).append(')'); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/WeakValuedCache.java b/main/commons/src/main/java/org/cryptomator/common/WeakValuedCache.java deleted file mode 100644 index 5dfa131bc..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/WeakValuedCache.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.cryptomator.common; - -import java.util.concurrent.ExecutionException; -import java.util.function.BiConsumer; -import java.util.function.Function; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.util.concurrent.ExecutionError; -import com.google.common.util.concurrent.UncheckedExecutionException; - -public class WeakValuedCache { - - private final LoadingCache delegate; - - private WeakValuedCache(Function loader) { - delegate = CacheBuilder.newBuilder() // - .weakValues() // - .build(new CacheLoader() { - @Override - public Value load(Key key) { - return loader.apply(key); - } - }); - } - - public static WeakValuedCache usingLoader(Function loader) { - return new WeakValuedCache<>(loader); - } - - public Value get(Key key) { - try { - return delegate.get(key); - } catch (ExecutionException e) { - throw new IllegalStateException("No checked exception can be thrown by loader", e); - } catch (UncheckedExecutionException e) { - throw (RuntimeException) e.getCause(); - } catch (ExecutionError e) { - throw (Error) e.getCause(); - } - } - - public void forEach(BiConsumer function) { - delegate.asMap().forEach(function); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java index a43c8cf83..cccd9808d 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java @@ -34,20 +34,19 @@ public class Settings { public static final String DEFAULT_GVFS_SCHEME = "dav"; public static final boolean DEFAULT_DEBUG_MODE = false; - private final Consumer saveCmd; - private final ObservableList directories = FXCollections.observableArrayList(); + private final ObservableList directories = FXCollections.observableArrayList(VaultSettings::observables); private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES); private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT); private final BooleanProperty useIpv6 = new SimpleBooleanProperty(DEFAULT_USE_IPV6); private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS); private final StringProperty preferredGvfsScheme = new SimpleStringProperty(DEFAULT_GVFS_SCHEME); private final BooleanProperty debugMode = new SimpleBooleanProperty(DEFAULT_DEBUG_MODE); + private Consumer saveCmd; /** * Package-private constructor; use {@link SettingsProvider}. */ - Settings(Consumer saveCmd) { - this.saveCmd = saveCmd; + Settings() { directories.addListener((ListChangeListener.Change change) -> this.save()); checkForUpdates.addListener(this::somethingChanged); port.addListener(this::somethingChanged); @@ -57,6 +56,10 @@ public class Settings { debugMode.addListener(this::somethingChanged); } + void setSaveCmd(Consumer saveCmd) { + this.saveCmd = saveCmd; + } + private void somethingChanged(ObservableValue observable, Object oldValue, Object newValue) { this.save(); } diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java index 1bb4ddbc8..cc1bc3792 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java @@ -8,7 +8,6 @@ package org.cryptomator.common.settings; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,13 +21,8 @@ public class SettingsJsonAdapter extends TypeAdapter { private static final Logger LOG = LoggerFactory.getLogger(SettingsJsonAdapter.class); - private final Consumer saveCmd; private final VaultSettingsJsonAdapter vaultSettingsJsonAdapter = new VaultSettingsJsonAdapter(); - public SettingsJsonAdapter(Consumer saveCmd) { - this.saveCmd = saveCmd; - } - @Override public void write(JsonWriter out, Settings value) throws IOException { out.beginObject(); @@ -53,14 +47,14 @@ public class SettingsJsonAdapter extends TypeAdapter { @Override public Settings read(JsonReader in) throws IOException { - Settings settings = new Settings(saveCmd); + Settings settings = new Settings(); in.beginObject(); while (in.hasNext()) { String name = in.nextName(); switch (name) { case "directories": - settings.getDirectories().addAll(readVaultSettingsArray(in, settings)); + settings.getDirectories().addAll(readVaultSettingsArray(in)); break; case "checkForUpdatesEnabled": settings.checkForUpdates().set(in.nextBoolean()); @@ -93,11 +87,11 @@ public class SettingsJsonAdapter extends TypeAdapter { return settings; } - private List readVaultSettingsArray(JsonReader in, Settings settings) throws IOException { + private List readVaultSettingsArray(JsonReader in) throws IOException { List result = new ArrayList<>(); in.beginArray(); while (!JsonToken.END_ARRAY.equals(in.peek())) { - result.add(vaultSettingsJsonAdapter.read(in, settings)); + result.add(vaultSettingsJsonAdapter.read(in)); } in.endArray(); return result; diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java index b413a7e23..2974252db 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java @@ -62,7 +62,7 @@ public class SettingsProvider implements Provider { private final ScheduledExecutorService saveScheduler = Executors.newSingleThreadScheduledExecutor(); private final AtomicReference> scheduledSaveCmd = new AtomicReference<>(); private final AtomicReference settings = new AtomicReference<>(); - private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter(this::scheduleSave); + private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter(); private final Gson gson; @Inject @@ -100,8 +100,9 @@ public class SettingsProvider implements Provider { LOG.info("Settings loaded from " + settingsPath); } catch (IOException e) { LOG.info("Failed to load settings, creating new one."); - settings = new Settings(this::scheduleSave); + settings = new Settings(); } + settings.setSaveCmd(this::scheduleSave); return settings; } diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 34e281aac..8ee82146f 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -15,41 +15,36 @@ import java.util.UUID; import org.apache.commons.lang3.StringUtils; import org.fxmisc.easybind.EasyBind; +import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import javafx.beans.value.ObservableValue; public class VaultSettings { + public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false; public static final boolean DEFAULT_MOUNT_AFTER_UNLOCK = true; public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true; - private final Settings settings; private final String id; private final ObjectProperty path = new SimpleObjectProperty<>(); private final StringProperty mountName = new SimpleStringProperty(); private final StringProperty winDriveLetter = new SimpleStringProperty(); + private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP); private final BooleanProperty mountAfterUnlock = new SimpleBooleanProperty(DEFAULT_MOUNT_AFTER_UNLOCK); private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT); - public VaultSettings(Settings settings, String id) { - this.settings = settings; + public VaultSettings(String id) { this.id = Objects.requireNonNull(id); EasyBind.subscribe(path, this::deriveMountNameFromPath); - path.addListener(this::somethingChanged); - mountName.addListener(this::somethingChanged); - winDriveLetter.addListener(this::somethingChanged); - mountAfterUnlock.addListener(this::somethingChanged); - revealAfterMount.addListener(this::somethingChanged); } - private void somethingChanged(ObservableValue observable, Object oldValue, Object newValue) { - settings.save(); + Observable[] observables() { + return new Observable[] {path, mountName, winDriveLetter, unlockAfterStartup, mountAfterUnlock, revealAfterMount}; } private void deriveMountNameFromPath(Path path) { @@ -58,8 +53,8 @@ public class VaultSettings { } } - public static VaultSettings withRandomId(Settings settings) { - return new VaultSettings(settings, generateId()); + public static VaultSettings withRandomId() { + return new VaultSettings(generateId()); } private static String generateId() { @@ -116,6 +111,10 @@ public class VaultSettings { return winDriveLetter; } + public BooleanProperty unlockAfterStartup() { + return unlockAfterStartup; + } + public BooleanProperty mountAfterUnlock() { return mountAfterUnlock; } diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java index 7fd9bc407..d1de6231e 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java @@ -24,18 +24,20 @@ class VaultSettingsJsonAdapter { out.name("path").value(value.path().get().toString()); out.name("mountName").value(value.mountName().get()); out.name("winDriveLetter").value(value.winDriveLetter().get()); + out.name("unlockAfterStartup").value(value.unlockAfterStartup().get()); out.name("mountAfterUnlock").value(value.mountAfterUnlock().get()); out.name("revealAfterMount").value(value.revealAfterMount().get()); out.endObject(); } - public VaultSettings read(JsonReader in, Settings settings) throws IOException { + public VaultSettings read(JsonReader in) throws IOException { String id = null; String path = null; String mountName = null; String winDriveLetter = null; - boolean mountAfterUnlock = true; - boolean revealAfterMount = true; + boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP; + boolean mountAfterUnlock = VaultSettings.DEFAULT_MOUNT_AFTER_UNLOCK; + boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT; in.beginObject(); while (in.hasNext()) { @@ -53,6 +55,9 @@ class VaultSettingsJsonAdapter { case "winDriveLetter": winDriveLetter = in.nextString(); break; + case "unlockAfterStartup": + unlockAfterStartup = in.nextBoolean(); + break; case "mountAfterUnlock": mountAfterUnlock = in.nextBoolean(); break; @@ -66,10 +71,11 @@ class VaultSettingsJsonAdapter { } in.endObject(); - VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId(settings) : new VaultSettings(settings, id); + VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id); vaultSettings.mountName().set(mountName); vaultSettings.path().set(Paths.get(path)); vaultSettings.winDriveLetter().set(winDriveLetter); + vaultSettings.unlockAfterStartup().set(unlockAfterStartup); vaultSettings.mountAfterUnlock().set(mountAfterUnlock); vaultSettings.revealAfterMount().set(revealAfterMount); return vaultSettings; diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingDoubleStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingDoubleStream.java deleted file mode 100644 index 60f571b6a..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingDoubleStream.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.cryptomator.common.streams.AutoClosingStreamFactory.AUTO_CLOSING_STREAM_FACTORY; - -import java.util.DoubleSummaryStatistics; -import java.util.OptionalDouble; -import java.util.function.BiConsumer; -import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleConsumer; -import java.util.function.DoublePredicate; -import java.util.function.ObjDoubleConsumer; -import java.util.function.Supplier; -import java.util.stream.DoubleStream; - -public class AutoClosingDoubleStream extends DelegatingDoubleStream { - - public static DoubleStream from(DoubleStream delegate) { - return new AutoClosingDoubleStream(delegate); - } - - public AutoClosingDoubleStream(DoubleStream delegate) { - super(delegate, AUTO_CLOSING_STREAM_FACTORY); - } - - @Override - public void forEach(DoubleConsumer action) { - try { - super.forEach(action); - } finally { - close(); - } - } - - @Override - public void forEachOrdered(DoubleConsumer action) { - try { - super.forEachOrdered(action); - } finally { - close(); - } - } - - @Override - public double[] toArray() { - try { - return super.toArray(); - } finally { - close(); - } - } - - @Override - public double reduce(double identity, DoubleBinaryOperator op) { - try { - return super.reduce(identity, op); - } finally { - close(); - } - } - - @Override - public OptionalDouble reduce(DoubleBinaryOperator op) { - try { - return super.reduce(op); - } finally { - close(); - } - } - - @Override - public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { - try { - return super.collect(supplier, accumulator, combiner); - } finally { - close(); - } - } - - @Override - public double sum() { - try { - return super.sum(); - } finally { - close(); - } - } - - @Override - public OptionalDouble min() { - try { - return super.min(); - } finally { - close(); - } - } - - @Override - public OptionalDouble max() { - try { - return super.max(); - } finally { - close(); - } - } - - @Override - public long count() { - try { - return super.count(); - } finally { - close(); - } - } - - @Override - public OptionalDouble average() { - try { - return super.average(); - } finally { - close(); - } - } - - @Override - public DoubleSummaryStatistics summaryStatistics() { - try { - return super.summaryStatistics(); - } finally { - close(); - } - } - - @Override - public boolean anyMatch(DoublePredicate predicate) { - try { - return super.anyMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean allMatch(DoublePredicate predicate) { - try { - return super.allMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean noneMatch(DoublePredicate predicate) { - try { - return super.noneMatch(predicate); - } finally { - close(); - } - } - - @Override - public OptionalDouble findFirst() { - try { - return super.findFirst(); - } finally { - close(); - } - } - - @Override - public OptionalDouble findAny() { - try { - return super.findAny(); - } finally { - close(); - } - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingIntStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingIntStream.java deleted file mode 100644 index dc3251574..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingIntStream.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.cryptomator.common.streams.AutoClosingStreamFactory.AUTO_CLOSING_STREAM_FACTORY; - -import java.util.IntSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.function.BiConsumer; -import java.util.function.IntBinaryOperator; -import java.util.function.IntConsumer; -import java.util.function.IntPredicate; -import java.util.function.ObjIntConsumer; -import java.util.function.Supplier; -import java.util.stream.IntStream; - -public class AutoClosingIntStream extends DelegatingIntStream { - - public static IntStream from(IntStream delegate) { - return new AutoClosingIntStream(delegate); - } - - public AutoClosingIntStream(IntStream delegate) { - super(delegate, AUTO_CLOSING_STREAM_FACTORY); - } - - @Override - public void forEach(IntConsumer action) { - try { - super.forEach(action); - } finally { - close(); - } - } - - @Override - public void forEachOrdered(IntConsumer action) { - try { - super.forEachOrdered(action); - } finally { - close(); - } - } - - @Override - public int[] toArray() { - try { - return super.toArray(); - } finally { - close(); - } - } - - @Override - public int reduce(int identity, IntBinaryOperator op) { - try { - return super.reduce(identity, op); - } finally { - close(); - } - } - - @Override - public OptionalInt reduce(IntBinaryOperator op) { - try { - return super.reduce(op); - } finally { - close(); - } - } - - @Override - public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { - try { - return super.collect(supplier, accumulator, combiner); - } finally { - close(); - } - } - - @Override - public int sum() { - try { - return super.sum(); - } finally { - close(); - } - } - - @Override - public OptionalInt min() { - try { - return super.min(); - } finally { - close(); - } - } - - @Override - public OptionalInt max() { - try { - return super.max(); - } finally { - close(); - } - } - - @Override - public long count() { - try { - return super.count(); - } finally { - close(); - } - } - - @Override - public OptionalDouble average() { - try { - return super.average(); - } finally { - close(); - } - } - - @Override - public IntSummaryStatistics summaryStatistics() { - try { - return super.summaryStatistics(); - } finally { - close(); - } - } - - @Override - public boolean anyMatch(IntPredicate predicate) { - try { - return super.anyMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean allMatch(IntPredicate predicate) { - try { - return super.allMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean noneMatch(IntPredicate predicate) { - try { - return super.noneMatch(predicate); - } finally { - close(); - } - } - - @Override - public OptionalInt findFirst() { - try { - return super.findFirst(); - } finally { - close(); - } - } - - @Override - public OptionalInt findAny() { - try { - return super.findAny(); - } finally { - close(); - } - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingLongStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingLongStream.java deleted file mode 100644 index 4bfc032de..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingLongStream.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.cryptomator.common.streams.AutoClosingStreamFactory.AUTO_CLOSING_STREAM_FACTORY; - -import java.util.LongSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalLong; -import java.util.function.BiConsumer; -import java.util.function.LongBinaryOperator; -import java.util.function.LongConsumer; -import java.util.function.LongPredicate; -import java.util.function.ObjLongConsumer; -import java.util.function.Supplier; -import java.util.stream.LongStream; - -public class AutoClosingLongStream extends DelegatingLongStream { - - public static LongStream from(LongStream delegate) { - return new AutoClosingLongStream(delegate); - } - - public AutoClosingLongStream(LongStream delegate) { - super(delegate, AUTO_CLOSING_STREAM_FACTORY); - } - - @Override - public void forEach(LongConsumer action) { - try { - super.forEach(action); - } finally { - close(); - } - } - - @Override - public void forEachOrdered(LongConsumer action) { - try { - super.forEachOrdered(action); - } finally { - close(); - } - } - - @Override - public long[] toArray() { - try { - return super.toArray(); - } finally { - close(); - } - } - - @Override - public long reduce(long identity, LongBinaryOperator op) { - try { - return super.reduce(identity, op); - } finally { - close(); - } - } - - @Override - public OptionalLong reduce(LongBinaryOperator op) { - try { - return super.reduce(op); - } finally { - close(); - } - } - - @Override - public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { - try { - return super.collect(supplier, accumulator, combiner); - } finally { - close(); - } - } - - @Override - public long sum() { - try { - return super.sum(); - } finally { - close(); - } - } - - @Override - public OptionalLong min() { - try { - return super.min(); - } finally { - close(); - } - } - - @Override - public OptionalLong max() { - try { - return super.max(); - } finally { - close(); - } - } - - @Override - public long count() { - try { - return super.count(); - } finally { - close(); - } - } - - @Override - public OptionalDouble average() { - try { - return super.average(); - } finally { - close(); - } - } - - @Override - public LongSummaryStatistics summaryStatistics() { - try { - return super.summaryStatistics(); - } finally { - close(); - } - } - - @Override - public boolean anyMatch(LongPredicate predicate) { - try { - return super.anyMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean allMatch(LongPredicate predicate) { - try { - return super.allMatch(predicate); - } finally { - close(); - } - } - - @Override - public boolean noneMatch(LongPredicate predicate) { - try { - return super.noneMatch(predicate); - } finally { - close(); - } - } - - @Override - public OptionalLong findFirst() { - try { - return super.findFirst(); - } finally { - close(); - } - } - - @Override - public OptionalLong findAny() { - try { - return super.findAny(); - } finally { - close(); - } - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStream.java deleted file mode 100644 index 7207bcf02..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStream.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.cryptomator.common.streams.AutoClosingStreamFactory.AUTO_CLOSING_STREAM_FACTORY; - -import java.util.Comparator; -import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.IntFunction; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Stream; - -/** - *

- * A Stream which is automatically closed after execution of a terminal operation. - *

- * Streams returned by intermediate operations are also auto closing. - *

- * Note: When using {@link #iterator()} or {@link #spliterator()} auto closing does not occur. - * - * @author Markus Kreusch - */ -public class AutoClosingStream extends DelegatingStream { - - public static Stream from(Stream delegate) { - return new AutoClosingStream<>(delegate); - } - - private AutoClosingStream(Stream delegate) { - super(delegate, AUTO_CLOSING_STREAM_FACTORY); - } - - public void forEach(Consumer action) { - try { - super.forEach(action); - } finally { - close(); - } - } - - public void forEachOrdered(Consumer action) { - try { - super.forEachOrdered(action); - } finally { - close(); - } - } - - public Object[] toArray() { - try { - return super.toArray(); - } finally { - close(); - } - } - - public A[] toArray(IntFunction generator) { - try { - return super.toArray(generator); - } finally { - close(); - } - } - - public T reduce(T identity, BinaryOperator accumulator) { - try { - return super.reduce(identity, accumulator); - } finally { - close(); - } - } - - public Optional reduce(BinaryOperator accumulator) { - try { - return super.reduce(accumulator); - } finally { - close(); - } - } - - public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { - try { - return super.reduce(identity, accumulator, combiner); - } finally { - close(); - } - } - - public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { - try { - return super.collect(supplier, accumulator, combiner); - } finally { - close(); - } - } - - public R collect(Collector collector) { - try { - return super.collect(collector); - } finally { - close(); - } - } - - public Optional min(Comparator comparator) { - try { - return super.min(comparator); - } finally { - close(); - } - } - - public Optional max(Comparator comparator) { - try { - return super.max(comparator); - } finally { - close(); - } - } - - public long count() { - try { - return super.count(); - } finally { - close(); - } - } - - public boolean anyMatch(Predicate predicate) { - try { - return super.anyMatch(predicate); - } finally { - close(); - } - } - - public boolean allMatch(Predicate predicate) { - try { - return super.allMatch(predicate); - } finally { - close(); - } - } - - public boolean noneMatch(Predicate predicate) { - try { - return super.noneMatch(predicate); - } finally { - close(); - } - } - - public Optional findFirst() { - try { - return super.findFirst(); - } finally { - close(); - } - } - - public Optional findAny() { - try { - return super.findAny(); - } finally { - close(); - } - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStreamFactory.java b/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStreamFactory.java deleted file mode 100644 index 18b8ab4d8..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/AutoClosingStreamFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -class AutoClosingStreamFactory implements DelegatingStreamFactory { - - public static final DelegatingStreamFactory AUTO_CLOSING_STREAM_FACTORY = new AutoClosingStreamFactory(); - - private AutoClosingStreamFactory() { - } - - @Override - public Stream from(Stream other) { - if (AutoClosingStream.class.isInstance(other)) { - return other; - } else { - return AutoClosingStream.from(other); - } - } - - @Override - public IntStream from(IntStream other) { - if (AutoClosingIntStream.class.isInstance(other)) { - return other; - } else { - return AutoClosingIntStream.from(other); - } - } - - @Override - public LongStream from(LongStream other) { - if (AutoClosingLongStream.class.isInstance(other)) { - return other; - } else { - return AutoClosingLongStream.from(other); - } - } - - @Override - public DoubleStream from(DoubleStream other) { - if (AutoClosingDoubleStream.class.isInstance(other)) { - return other; - } else { - return AutoClosingDoubleStream.from(other); - } - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingDoubleStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingDoubleStream.java deleted file mode 100644 index 8fca0e7fd..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingDoubleStream.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.DoubleSummaryStatistics; -import java.util.OptionalDouble; -import java.util.PrimitiveIterator.OfDouble; -import java.util.function.BiConsumer; -import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleConsumer; -import java.util.function.DoubleFunction; -import java.util.function.DoublePredicate; -import java.util.function.DoubleToIntFunction; -import java.util.function.DoubleToLongFunction; -import java.util.function.DoubleUnaryOperator; -import java.util.function.ObjDoubleConsumer; -import java.util.function.Supplier; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -abstract class DelegatingDoubleStream implements DoubleStream { - - private final DoubleStream delegate; - private final DelegatingStreamFactory wrapper; - - public DelegatingDoubleStream(DoubleStream delegate, DelegatingStreamFactory wrapper) { - this.delegate = delegate; - this.wrapper = wrapper; - } - - public DoubleStream filter(DoublePredicate predicate) { - return wrapper.from(delegate.filter(predicate)); - } - - public boolean isParallel() { - return delegate.isParallel(); - } - - public DoubleStream map(DoubleUnaryOperator mapper) { - return wrapper.from(delegate.map(mapper)); - } - - public Stream mapToObj(DoubleFunction mapper) { - return wrapper.from(delegate.mapToObj(mapper)); - } - - public DoubleStream unordered() { - return wrapper.from(delegate.unordered()); - } - - public DoubleStream onClose(Runnable closeHandler) { - return wrapper.from(delegate.onClose(closeHandler)); - } - - public IntStream mapToInt(DoubleToIntFunction mapper) { - return wrapper.from(delegate.mapToInt(mapper)); - } - - public LongStream mapToLong(DoubleToLongFunction mapper) { - return wrapper.from(delegate.mapToLong(mapper)); - } - - public void close() { - delegate.close(); - } - - public DoubleStream flatMap(DoubleFunction mapper) { - return wrapper.from(delegate.flatMap(mapper)); - } - - public DoubleStream distinct() { - return wrapper.from(delegate.distinct()); - } - - public DoubleStream sorted() { - return wrapper.from(delegate.sorted()); - } - - public DoubleStream peek(DoubleConsumer action) { - return wrapper.from(delegate.peek(action)); - } - - public DoubleStream limit(long maxSize) { - return wrapper.from(delegate.limit(maxSize)); - } - - public DoubleStream skip(long n) { - return wrapper.from(delegate.skip(n)); - } - - public void forEach(DoubleConsumer action) { - delegate.forEach(action); - } - - public void forEachOrdered(DoubleConsumer action) { - delegate.forEachOrdered(action); - } - - public double[] toArray() { - return delegate.toArray(); - } - - public double reduce(double identity, DoubleBinaryOperator op) { - return delegate.reduce(identity, op); - } - - public OptionalDouble reduce(DoubleBinaryOperator op) { - return delegate.reduce(op); - } - - public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { - return delegate.collect(supplier, accumulator, combiner); - } - - public double sum() { - return delegate.sum(); - } - - public OptionalDouble min() { - return delegate.min(); - } - - public OptionalDouble max() { - return delegate.max(); - } - - public long count() { - return delegate.count(); - } - - public OptionalDouble average() { - return delegate.average(); - } - - public DoubleSummaryStatistics summaryStatistics() { - return delegate.summaryStatistics(); - } - - public boolean anyMatch(DoublePredicate predicate) { - return delegate.anyMatch(predicate); - } - - public boolean allMatch(DoublePredicate predicate) { - return delegate.allMatch(predicate); - } - - public boolean noneMatch(DoublePredicate predicate) { - return delegate.noneMatch(predicate); - } - - public OptionalDouble findFirst() { - return delegate.findFirst(); - } - - public OptionalDouble findAny() { - return delegate.findAny(); - } - - public Stream boxed() { - return wrapper.from(delegate.boxed()); - } - - public DoubleStream sequential() { - return wrapper.from(delegate.sequential()); - } - - public DoubleStream parallel() { - return wrapper.from(delegate.parallel()); - } - - public OfDouble iterator() { - return delegate.iterator(); - } - - public java.util.Spliterator.OfDouble spliterator() { - return delegate.spliterator(); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingIntStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingIntStream.java deleted file mode 100644 index f3ee72e16..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingIntStream.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.IntSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.PrimitiveIterator.OfInt; -import java.util.function.BiConsumer; -import java.util.function.IntBinaryOperator; -import java.util.function.IntConsumer; -import java.util.function.IntFunction; -import java.util.function.IntPredicate; -import java.util.function.IntToDoubleFunction; -import java.util.function.IntToLongFunction; -import java.util.function.IntUnaryOperator; -import java.util.function.ObjIntConsumer; -import java.util.function.Supplier; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -abstract class DelegatingIntStream implements IntStream { - - private final IntStream delegate; - private final DelegatingStreamFactory wrapper; - - public DelegatingIntStream(IntStream delegate, DelegatingStreamFactory wrapper) { - this.delegate = delegate; - this.wrapper = wrapper; - } - - public IntStream filter(IntPredicate predicate) { - return wrapper.from(delegate.filter(predicate)); - } - - public boolean isParallel() { - return delegate.isParallel(); - } - - public IntStream map(IntUnaryOperator mapper) { - return wrapper.from(delegate.map(mapper)); - } - - public Stream mapToObj(IntFunction mapper) { - return wrapper.from(delegate.mapToObj(mapper)); - } - - public IntStream unordered() { - return wrapper.from(delegate.unordered()); - } - - public LongStream mapToLong(IntToLongFunction mapper) { - return wrapper.from(delegate.mapToLong(mapper)); - } - - public IntStream onClose(Runnable closeHandler) { - return wrapper.from(delegate.onClose(closeHandler)); - } - - public DoubleStream mapToDouble(IntToDoubleFunction mapper) { - return wrapper.from(delegate.mapToDouble(mapper)); - } - - public void close() { - delegate.close(); - } - - public IntStream flatMap(IntFunction mapper) { - return wrapper.from(delegate.flatMap(mapper)); - } - - public IntStream distinct() { - return wrapper.from(delegate.distinct()); - } - - public IntStream sorted() { - return wrapper.from(delegate.sorted()); - } - - public IntStream peek(IntConsumer action) { - return wrapper.from(delegate.peek(action)); - } - - public IntStream limit(long maxSize) { - return wrapper.from(delegate.limit(maxSize)); - } - - public IntStream skip(long n) { - return wrapper.from(delegate.skip(n)); - } - - public void forEach(IntConsumer action) { - delegate.forEach(action); - } - - public void forEachOrdered(IntConsumer action) { - delegate.forEachOrdered(action); - } - - public int[] toArray() { - return delegate.toArray(); - } - - public int reduce(int identity, IntBinaryOperator op) { - return delegate.reduce(identity, op); - } - - public OptionalInt reduce(IntBinaryOperator op) { - return delegate.reduce(op); - } - - public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { - return delegate.collect(supplier, accumulator, combiner); - } - - public int sum() { - return delegate.sum(); - } - - public OptionalInt min() { - return delegate.min(); - } - - public OptionalInt max() { - return delegate.max(); - } - - public long count() { - return delegate.count(); - } - - public OptionalDouble average() { - return delegate.average(); - } - - public IntSummaryStatistics summaryStatistics() { - return delegate.summaryStatistics(); - } - - public boolean anyMatch(IntPredicate predicate) { - return delegate.anyMatch(predicate); - } - - public boolean allMatch(IntPredicate predicate) { - return delegate.allMatch(predicate); - } - - public boolean noneMatch(IntPredicate predicate) { - return delegate.noneMatch(predicate); - } - - public OptionalInt findFirst() { - return delegate.findFirst(); - } - - public OptionalInt findAny() { - return delegate.findAny(); - } - - public LongStream asLongStream() { - return wrapper.from(delegate.asLongStream()); - } - - public DoubleStream asDoubleStream() { - return wrapper.from(delegate.asDoubleStream()); - } - - public Stream boxed() { - return wrapper.from(delegate.boxed()); - } - - public IntStream sequential() { - return wrapper.from(delegate.sequential()); - } - - public IntStream parallel() { - return wrapper.from(delegate.parallel()); - } - - public OfInt iterator() { - return delegate.iterator(); - } - - public java.util.Spliterator.OfInt spliterator() { - return delegate.spliterator(); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingLongStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingLongStream.java deleted file mode 100644 index c33baef4f..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingLongStream.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.LongSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalLong; -import java.util.PrimitiveIterator.OfLong; -import java.util.function.BiConsumer; -import java.util.function.LongBinaryOperator; -import java.util.function.LongConsumer; -import java.util.function.LongFunction; -import java.util.function.LongPredicate; -import java.util.function.LongToDoubleFunction; -import java.util.function.LongToIntFunction; -import java.util.function.LongUnaryOperator; -import java.util.function.ObjLongConsumer; -import java.util.function.Supplier; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -abstract class DelegatingLongStream implements LongStream { - - private final LongStream delegate; - private final DelegatingStreamFactory wrapper; - - public DelegatingLongStream(LongStream delegate, DelegatingStreamFactory wrapper) { - this.delegate = delegate; - this.wrapper = wrapper; - } - - public LongStream filter(LongPredicate predicate) { - return wrapper.from(delegate.filter(predicate)); - } - - public boolean isParallel() { - return delegate.isParallel(); - } - - public LongStream map(LongUnaryOperator mapper) { - return wrapper.from(delegate.map(mapper)); - } - - public Stream mapToObj(LongFunction mapper) { - return wrapper.from(delegate.mapToObj(mapper)); - } - - public LongStream unordered() { - return wrapper.from(delegate.unordered()); - } - - public LongStream onClose(Runnable closeHandler) { - return wrapper.from(delegate.onClose(closeHandler)); - } - - public IntStream mapToInt(LongToIntFunction mapper) { - return wrapper.from(delegate.mapToInt(mapper)); - } - - public DoubleStream mapToDouble(LongToDoubleFunction mapper) { - return wrapper.from(delegate.mapToDouble(mapper)); - } - - public void close() { - delegate.close(); - } - - public LongStream flatMap(LongFunction mapper) { - return wrapper.from(delegate.flatMap(mapper)); - } - - public LongStream distinct() { - return wrapper.from(delegate.distinct()); - } - - public LongStream sorted() { - return wrapper.from(delegate.sorted()); - } - - public LongStream peek(LongConsumer action) { - return wrapper.from(delegate.peek(action)); - } - - public LongStream limit(long maxSize) { - return wrapper.from(delegate.limit(maxSize)); - } - - public LongStream skip(long n) { - return wrapper.from(delegate.skip(n)); - } - - public void forEach(LongConsumer action) { - delegate.forEach(action); - } - - public void forEachOrdered(LongConsumer action) { - delegate.forEachOrdered(action); - } - - public long[] toArray() { - return delegate.toArray(); - } - - public long reduce(long identity, LongBinaryOperator op) { - return delegate.reduce(identity, op); - } - - public OptionalLong reduce(LongBinaryOperator op) { - return delegate.reduce(op); - } - - public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { - return delegate.collect(supplier, accumulator, combiner); - } - - public long sum() { - return delegate.sum(); - } - - public OptionalLong min() { - return delegate.min(); - } - - public OptionalLong max() { - return delegate.max(); - } - - public long count() { - return delegate.count(); - } - - public OptionalDouble average() { - return delegate.average(); - } - - public LongSummaryStatistics summaryStatistics() { - return delegate.summaryStatistics(); - } - - public boolean anyMatch(LongPredicate predicate) { - return delegate.anyMatch(predicate); - } - - public boolean allMatch(LongPredicate predicate) { - return delegate.allMatch(predicate); - } - - public boolean noneMatch(LongPredicate predicate) { - return delegate.noneMatch(predicate); - } - - public OptionalLong findFirst() { - return delegate.findFirst(); - } - - public OptionalLong findAny() { - return delegate.findAny(); - } - - public DoubleStream asDoubleStream() { - return wrapper.from(delegate.asDoubleStream()); - } - - public Stream boxed() { - return wrapper.from(delegate.boxed()); - } - - public LongStream sequential() { - return wrapper.from(delegate.sequential()); - } - - public LongStream parallel() { - return wrapper.from(delegate.parallel()); - } - - public OfLong iterator() { - return delegate.iterator(); - } - - public java.util.Spliterator.OfLong spliterator() { - return delegate.spliterator(); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStream.java b/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStream.java deleted file mode 100644 index 585bb8cd3..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStream.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.Comparator; -import java.util.Iterator; -import java.util.Optional; -import java.util.Spliterator; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.IntFunction; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.function.ToDoubleFunction; -import java.util.function.ToIntFunction; -import java.util.function.ToLongFunction; -import java.util.stream.Collector; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -abstract class DelegatingStream implements Stream { - - private final Stream delegate; - private final DelegatingStreamFactory wrapper; - - protected DelegatingStream(Stream delegate, DelegatingStreamFactory wrapper) { - this.delegate = delegate; - this.wrapper = wrapper; - } - - public Iterator iterator() { - return delegate.iterator(); - } - - public Spliterator spliterator() { - return delegate.spliterator(); - } - - public boolean isParallel() { - return delegate.isParallel(); - } - - public Stream sequential() { - return wrapper.from(delegate.sequential()); - } - - public Stream parallel() { - return wrapper.from(delegate.parallel()); - } - - public Stream unordered() { - return wrapper.from(delegate.unordered()); - } - - public Stream onClose(Runnable closeHandler) { - return wrapper.from(delegate.onClose(closeHandler)); - } - - public void close() { - delegate.close(); - } - - public Stream filter(Predicate predicate) { - return wrapper.from(delegate.filter(predicate)); - } - - public Stream map(Function mapper) { - return wrapper.from(delegate.map(mapper)); - } - - public IntStream mapToInt(ToIntFunction mapper) { - return wrapper.from(delegate.mapToInt(mapper)); - } - - public LongStream mapToLong(ToLongFunction mapper) { - return wrapper.from(delegate.mapToLong(mapper)); - } - - public DoubleStream mapToDouble(ToDoubleFunction mapper) { - return wrapper.from(delegate.mapToDouble(mapper)); - } - - public Stream flatMap(Function> mapper) { - return wrapper.from(delegate.flatMap(mapper)); - } - - public IntStream flatMapToInt(Function mapper) { - return wrapper.from(delegate.flatMapToInt(mapper)); - } - - public LongStream flatMapToLong(Function mapper) { - return wrapper.from(delegate.flatMapToLong(mapper)); - } - - public DoubleStream flatMapToDouble(Function mapper) { - return wrapper.from(delegate.flatMapToDouble(mapper)); - } - - public Stream distinct() { - return wrapper.from(delegate.distinct()); - } - - public Stream sorted() { - return wrapper.from(delegate.sorted()); - } - - public Stream sorted(Comparator comparator) { - return wrapper.from(delegate.sorted(comparator)); - } - - public Stream peek(Consumer action) { - return wrapper.from(delegate.peek(action)); - } - - public Stream limit(long maxSize) { - return wrapper.from(delegate.limit(maxSize)); - } - - public Stream skip(long n) { - return wrapper.from(delegate.skip(n)); - } - - public void forEach(Consumer action) { - delegate.forEach(action); - } - - public void forEachOrdered(Consumer action) { - delegate.forEachOrdered(action); - } - - public Object[] toArray() { - return delegate.toArray(); - } - - public A[] toArray(IntFunction generator) { - return delegate.toArray(generator); - } - - public T reduce(T identity, BinaryOperator accumulator) { - return delegate.reduce(identity, accumulator); - } - - public Optional reduce(BinaryOperator accumulator) { - return delegate.reduce(accumulator); - } - - public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { - return delegate.reduce(identity, accumulator, combiner); - } - - public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { - return delegate.collect(supplier, accumulator, combiner); - } - - public R collect(Collector collector) { - return delegate.collect(collector); - } - - public Optional min(Comparator comparator) { - return delegate.min(comparator); - } - - public Optional max(Comparator comparator) { - return delegate.max(comparator); - } - - public long count() { - return delegate.count(); - } - - public boolean anyMatch(Predicate predicate) { - return delegate.anyMatch(predicate); - } - - public boolean allMatch(Predicate predicate) { - return delegate.allMatch(predicate); - } - - public boolean noneMatch(Predicate predicate) { - return delegate.noneMatch(predicate); - } - - public Optional findFirst() { - return delegate.findFirst(); - } - - public Optional findAny() { - return delegate.findAny(); - } - -} diff --git a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStreamFactory.java b/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStreamFactory.java deleted file mode 100644 index 24203baf8..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/streams/DelegatingStreamFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.cryptomator.common.streams; - -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -public interface DelegatingStreamFactory { - - Stream from(Stream other); - - IntStream from(IntStream other); - - LongStream from(LongStream other); - - DoubleStream from(DoubleStream other); - - public interface ObjectStreamWrapper { - Stream from(Stream other); - } - -} \ No newline at end of file diff --git a/main/commons/src/test/java/org/cryptomator/common/CachingSupplierTest.java b/main/commons/src/test/java/org/cryptomator/common/CachingSupplierTest.java deleted file mode 100644 index 4917c5eac..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/CachingSupplierTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.cryptomator.common; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.function.Supplier; - -import org.junit.Test; - -public class CachingSupplierTest { - - @Test - public void testInvokingGetInvokesDelegate() { - @SuppressWarnings("unchecked") - Supplier delegate = mock(Supplier.class); - Object expectedResult = new Object(); - when(delegate.get()).thenReturn(expectedResult); - Supplier inTest = CachingSupplier.from(delegate); - - Object result = inTest.get(); - - assertThat(result, is(expectedResult)); - } - - @Test - public void testInvokingGetTwiceDoesNotInvokeDelegateTwice() { - @SuppressWarnings("unchecked") - Supplier delegate = mock(Supplier.class); - Object expectedResult = new Object(); - when(delegate.get()).thenReturn(expectedResult); - Supplier inTest = CachingSupplier.from(delegate); - - inTest.get(); - Object result = inTest.get(); - - assertThat(result, is(expectedResult)); - verify(delegate).get(); - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/HolderTest.java b/main/commons/src/test/java/org/cryptomator/common/HolderTest.java deleted file mode 100644 index ad71e866f..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/HolderTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.cryptomator.common; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -public class HolderTest { - - private static final Object INITIAL = new Object(); - private static final Object VALUE = new Object(); - - private Holder inTest = new Holder<>(INITIAL); - - @Test - public void testInitialValueIsInitial() { - assertThat(inTest.get(), is(INITIAL)); - } - - @Test - public void testSetChangesValue() { - inTest.set(VALUE); - - assertThat(inTest.get(), is(VALUE)); - } - - @Test - public void testAcceptChangesValue() { - inTest.accept(VALUE); - - assertThat(inTest.get(), is(VALUE)); - } - - @Test - public void testResetChangesValueToInitial() { - inTest.set(VALUE); - inTest.reset(); - - assertThat(inTest.get(), is(INITIAL)); - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/WeakValuedCacheTest.java b/main/commons/src/test/java/org/cryptomator/common/WeakValuedCacheTest.java deleted file mode 100644 index d9d1b009d..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/WeakValuedCacheTest.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.cryptomator.common; - -import static java.lang.String.format; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.sameInstance; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.function.Function; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; - -public class WeakValuedCacheTest { - - private final String A_KEY = "aKey"; - private final String ANOTHER_KEY = "anotherKey"; - - private WeakValuedCache inTest; - - private Function loader; - - @SuppressWarnings("unchecked") - @Before - public void setup() { - loader = Mockito.mock(Function.class); - inTest = WeakValuedCache.usingLoader(loader); - } - - @Test - public void testResultOfGetIsResultOfLoaderForTheSameKey() { - Value theValue = new Value(); - Value theOtherValue = new Value(); - when(loader.apply(A_KEY)).thenReturn(theValue); - when(loader.apply(ANOTHER_KEY)).thenReturn(theOtherValue); - - Value result = inTest.get(A_KEY); - Value anotherResult = inTest.get(ANOTHER_KEY); - - assertThat(result, is(sameInstance(theValue))); - assertThat(anotherResult, is(sameInstance(theOtherValue))); - } - - @Test - public void testCachedResultIsResultOfLoaderForTheSameKey() { - Value theValue = new Value(); - Value theOtherValue = new Value(); - when(loader.apply(A_KEY)).thenReturn(theValue); - when(loader.apply(ANOTHER_KEY)).thenReturn(theOtherValue); - - inTest.get(A_KEY); - inTest.get(ANOTHER_KEY); - Value result = inTest.get(A_KEY); - Value anotherResult = inTest.get(ANOTHER_KEY); - - assertThat(result, is(sameInstance(theValue))); - assertThat(anotherResult, is(sameInstance(theOtherValue))); - } - - @Test - public void testTwiceInvocationOfGetDoesNotInvokeLoaderTwice() { - Value theValue = new Value(); - when(loader.apply(A_KEY)).thenReturn(theValue); - - inTest.get(A_KEY); - inTest.get(A_KEY); - - verify(loader).apply(A_KEY); - } - - @Test - public void testSecondInvocationOfGetReturnsTheSameResult() { - Value theValue = new Value(); - when(loader.apply(A_KEY)).thenReturn(theValue); - - inTest.get(A_KEY); - Value result = inTest.get(A_KEY); - - assertThat(result, is(sameInstance(theValue))); - } - - @Ignore - @Test - public void testCacheDoesNotPreventGarbageCollectionOfValues() { - when(loader.apply(A_KEY)).thenAnswer(this::createValueUsingMoreThanHalfTheJvmMemory); - - inTest.get(A_KEY); - - // force garbage collection of previously created value by creating an - // object so large it can not coexist with the value - createObjectUsingMoreThanHalfTheJvmMemory(); - } - - @Test(expected = RuntimeExceptionThrownInLoader.class) - public void testCacheRethrowsRuntimeExceptionsFromLoader() { - when(loader.apply(A_KEY)).thenThrow(new RuntimeExceptionThrownInLoader()); - - inTest.get(A_KEY); - } - - @Test(expected = ErrorThrownInLoader.class) - public void testCacheRethrowsErrorsFromLoader() { - when(loader.apply(A_KEY)).thenThrow(new ErrorThrownInLoader()); - - inTest.get(A_KEY); - } - - private Value createValueUsingMoreThanHalfTheJvmMemory(InvocationOnMock invocation) { - Object data = createObjectUsingMoreThanHalfTheJvmMemory(); - Value value = new Value(); - value.setPayload(data); - return value; - } - - private Object createObjectUsingMoreThanHalfTheJvmMemory() { - long maxMemory = Runtime.getRuntime().maxMemory(); - long moreThanHalfTheJvmMemory = maxMemory / 2 + 1; - return createObjectUsingAtLeast(moreThanHalfTheJvmMemory); - } - - private Object createObjectUsingAtLeast(long minMemory) { - if (minMemory <= Integer.MAX_VALUE) { - return new byte[(int) minMemory]; - } else if ((minMemory / Integer.MAX_VALUE) <= Integer.MAX_VALUE) { - int numberOfArraysWithMaxIntSize = (int) (minMemory / Integer.MAX_VALUE); - int numberOfRemainingBytes = (int) (minMemory - Integer.MAX_VALUE * numberOfArraysWithMaxIntSize); - return new byte[][][] { // - new byte[numberOfArraysWithMaxIntSize][Integer.MAX_VALUE], // - new byte[1][numberOfRemainingBytes] // - }; - } else { - throw new IllegalArgumentException(format("Can not create object with more than 3.999999996 Exabyte")); - } - } - - private static class RuntimeExceptionThrownInLoader extends RuntimeException { - } - - private static class ErrorThrownInLoader extends Error { - } - - private static class Value { - - @SuppressWarnings("unused") - private Object payload; - - public void setPayload(Object payload) { - this.payload = payload; - } - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java index 6b32a06b3..23ddaab1d 100644 --- a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java @@ -12,10 +12,7 @@ import org.junit.Test; public class SettingsJsonAdapterTest { - private final SettingsJsonAdapter adapter = new SettingsJsonAdapter(this::noop); - - private void noop(Settings settings) { - } + private final SettingsJsonAdapter adapter = new SettingsJsonAdapter(); @Test public void testDeserialize() throws IOException { diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java new file mode 100644 index 000000000..fcce53253 --- /dev/null +++ b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java @@ -0,0 +1,33 @@ +package org.cryptomator.common.settings; + +import java.io.IOException; +import java.util.function.Consumer; + +import org.junit.Test; +import org.mockito.Mockito; + +public class SettingsTest { + + @Test + public void testAutoSave() throws IOException { + @SuppressWarnings("unchecked") + Consumer changeListener = Mockito.mock(Consumer.class); + Settings settings = new Settings(); + settings.setSaveCmd(changeListener); + VaultSettings vaultSettings = VaultSettings.withRandomId(); + Mockito.verify(changeListener, Mockito.times(0)).accept(settings); + + // first change (to property): + settings.preferredGvfsScheme().set("asd"); + Mockito.verify(changeListener, Mockito.times(1)).accept(settings); + + // second change (to list): + settings.getDirectories().add(vaultSettings); + Mockito.verify(changeListener, Mockito.times(2)).accept(settings); + + // third change (to property of list item): + vaultSettings.mountName().set("asd"); + Mockito.verify(changeListener, Mockito.times(3)).accept(settings); + } + +} diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java index 0c2604e10..7320b6768 100644 --- a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java @@ -11,7 +11,6 @@ import java.nio.file.Paths; import org.junit.Assert; import org.junit.Test; -import org.mockito.Mockito; import com.google.gson.stream.JsonReader; @@ -23,9 +22,8 @@ public class VaultSettingsJsonAdapterTest { public void testDeserialize() throws IOException { String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"mountName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true}"; JsonReader jsonReader = new JsonReader(new StringReader(json)); - Settings settings = Mockito.mock(Settings.class); - VaultSettings vaultSettings = adapter.read(jsonReader, settings); + VaultSettings vaultSettings = adapter.read(jsonReader); Assert.assertEquals("foo", vaultSettings.getId()); Assert.assertEquals(Paths.get("/foo/bar"), vaultSettings.path().get()); Assert.assertEquals("test", vaultSettings.mountName().get()); diff --git a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingDoubleStreamTest.java b/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingDoubleStreamTest.java deleted file mode 100644 index 5a8215ad8..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingDoubleStreamTest.java +++ /dev/null @@ -1,227 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.DoubleSummaryStatistics; -import java.util.List; -import java.util.OptionalDouble; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleConsumer; -import java.util.function.DoubleFunction; -import java.util.function.DoublePredicate; -import java.util.function.DoubleToIntFunction; -import java.util.function.DoubleToLongFunction; -import java.util.function.DoubleUnaryOperator; -import java.util.function.Function; -import java.util.function.ObjDoubleConsumer; -import java.util.function.Supplier; -import java.util.stream.BaseStream; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.InOrder; - -@SuppressWarnings({"unchecked", "rawtypes"}) -@RunWith(Theories.class) -public class AutoClosingDoubleStreamTest { - - private static final DoublePredicate A_DOUBLE_PREDICATE = any -> true; - private static final DoubleFunction A_DOUBLE_FUNCTION = i -> null; - private static final BiConsumer A_BICONSUMER = (a, b) -> { - }; - private static final Supplier A_SUPPLIER = () -> null; - - @DataPoints("intermediateOperations") - public static final List> INTERMEDIATE_OPERATIONS = new ArrayList<>(); - - @DataPoints("terminalOperations") - public static final List> TERMINAL_OPERATIONS = new ArrayList<>(); - private static final DoubleUnaryOperator A_DOUBLE_UNARY_OPERATOR = i -> 3; - private static final DoubleToLongFunction A_DOUBLE_TO_LONG_FUNCTION = i -> 3L; - private static final DoubleToIntFunction A_DOUBLE_TO_INT_FUNCTION = i -> 5; - private static final DoubleConsumer A_DOUBLE_CONSUMER = i -> { - }; - private static final ObjDoubleConsumer AN_OBJ_DOUBLE_CONSUMER = (a, b) -> { - }; - private static final DoubleBinaryOperator A_DOUBLE_BINARY_OPERATOR = (a, b) -> a; - - static { - // define intermediate operations - test(DoubleStream.class, DoubleStream::distinct); - test(DoubleStream.class, stream -> stream.filter(A_DOUBLE_PREDICATE)); - test(DoubleStream.class, stream -> stream.flatMap(A_DOUBLE_FUNCTION)); - test(DoubleStream.class, stream -> stream.limit(5)); - test(DoubleStream.class, stream -> stream.map(A_DOUBLE_UNARY_OPERATOR)); - test(LongStream.class, stream -> stream.mapToLong(A_DOUBLE_TO_LONG_FUNCTION)); - test(Stream.class, stream -> stream.mapToObj(A_DOUBLE_FUNCTION)); - test(IntStream.class, stream -> stream.mapToInt(A_DOUBLE_TO_INT_FUNCTION)); - test(DoubleStream.class, DoubleStream::parallel); - test(DoubleStream.class, stream -> stream.peek(A_DOUBLE_CONSUMER)); - test(DoubleStream.class, DoubleStream::sequential); - test(DoubleStream.class, stream -> stream.skip(5)); - test(DoubleStream.class, DoubleStream::sorted); - test(DoubleStream.class, DoubleStream::unordered); - test(Stream.class, DoubleStream::boxed); - - // define terminal operations - test(stream -> stream.allMatch(A_DOUBLE_PREDICATE), true); - test(stream -> stream.anyMatch(A_DOUBLE_PREDICATE), true); - test(stream -> stream.collect(A_SUPPLIER, AN_OBJ_DOUBLE_CONSUMER, A_BICONSUMER), 7d); - test(DoubleStream::count, 3L); - test(DoubleStream::findAny, OptionalDouble.of(3)); - test(DoubleStream::findFirst, OptionalDouble.of(3)); - test(stream -> stream.forEach(A_DOUBLE_CONSUMER)); - test(stream -> stream.forEachOrdered(A_DOUBLE_CONSUMER)); - test(stream -> stream.max(), OptionalDouble.of(3)); - test(stream -> stream.min(), OptionalDouble.of(3)); - test(stream -> stream.noneMatch(A_DOUBLE_PREDICATE), true); - test(stream -> stream.reduce(A_DOUBLE_BINARY_OPERATOR), OptionalDouble.of(3)); - test(stream -> stream.reduce(1, A_DOUBLE_BINARY_OPERATOR), 3d); - test(DoubleStream::toArray, new double[1]); - test(DoubleStream::sum, 1d); - test(DoubleStream::average, OptionalDouble.of(3d)); - test(DoubleStream::summaryStatistics, new DoubleSummaryStatistics()); - } - - private static void test(Consumer consumer) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return null; - } - - @Override - public T apply(DoubleStream stream) { - consumer.accept(stream); - return null; - } - }); - } - - private static void test(Function function, T result) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return result; - } - - @Override - public T apply(DoubleStream stream) { - return function.apply(stream); - } - }); - } - - private static void test(Class type, Function function) { - INTERMEDIATE_OPERATIONS.add(new DoubleermediateOperation() { - @Override - public Class type() { - return type; - } - - @Override - public T apply(DoubleStream stream) { - return function.apply(stream); - } - }); - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private DoubleStream delegate; - private DoubleStream inTest; - - @Before - public void setUp() { - delegate = mock(DoubleStream.class); - inTest = AutoClosingDoubleStream.from(delegate); - } - - @Theory - public void testIntermediateOperationReturnsNewAutoClosingStream(@FromDataPoints("intermediateOperations") DoubleermediateOperation intermediateOperation) { - BaseStream newDelegate = (BaseStream) mock(intermediateOperation.type()); - when(intermediateOperation.apply(delegate)).thenReturn(newDelegate); - - BaseStream result = intermediateOperation.apply(inTest); - - assertThat(result, isAutoClosing()); - verifyDelegate(result, newDelegate); - } - - @Theory - public void testTerminalOperationDelegatesToAndClosesDelegate(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - Object expectedResult = terminalOperation.result(); - if (expectedResult != null) { - when(terminalOperation.apply(delegate)).thenReturn(expectedResult); - } - - Object result = terminalOperation.apply(inTest); - - InOrder inOrder = inOrder(delegate); - assertThat(result, is(expectedResult)); - inOrder.verify(delegate).close(); - } - - @Theory - public void testTerminalOperationClosesDelegateEvenOnException(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - RuntimeException exception = new RuntimeException(); - terminalOperation.apply(doThrow(exception).when(delegate)); - - thrown.expect(is(exception)); - - try { - terminalOperation.apply(inTest); - } finally { - verify(delegate).close(); - } - } - - private Matcher isAutoClosing() { - return is(anyOf(instanceOf(AutoClosingStream.class), instanceOf(AutoClosingDoubleStream.class), instanceOf(AutoClosingIntStream.class), instanceOf(AutoClosingLongStream.class))); - } - - private void verifyDelegate(BaseStream result, BaseStream newDelegate) { - result.close(); - verify(newDelegate).close(); - } - - private interface TerminalOperation { - - T result(); - - T apply(DoubleStream stream); - - } - - private interface DoubleermediateOperation { - - Class type(); - - T apply(DoubleStream stream); - - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingIntStreamTest.java b/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingIntStreamTest.java deleted file mode 100644 index d86718b62..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingIntStreamTest.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.IntSummaryStatistics; -import java.util.List; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.IntBinaryOperator; -import java.util.function.IntConsumer; -import java.util.function.IntFunction; -import java.util.function.IntPredicate; -import java.util.function.IntToDoubleFunction; -import java.util.function.IntToLongFunction; -import java.util.function.IntUnaryOperator; -import java.util.function.ObjIntConsumer; -import java.util.function.Supplier; -import java.util.stream.BaseStream; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.InOrder; - -@SuppressWarnings({"unchecked", "rawtypes"}) -@RunWith(Theories.class) -public class AutoClosingIntStreamTest { - - private static final IntPredicate AN_INT_PREDICATE = any -> true; - private static final IntFunction AN_INT_FUNCTION = i -> null; - private static final BiConsumer A_BICONSUMER = (a, b) -> { - }; - private static final Supplier A_SUPPLIER = () -> null; - - @DataPoints("intermediateOperations") - public static final List> INTERMEDIATE_OPERATIONS = new ArrayList<>(); - - @DataPoints("terminalOperations") - public static final List> TERMINAL_OPERATIONS = new ArrayList<>(); - private static final IntUnaryOperator AN_INT_UNARY_OPERATOR = i -> 3; - private static final IntToDoubleFunction AN_INT_TO_DOUBLE_FUNCTION = i -> 3d; - private static final IntToLongFunction AN_INT_TO_LONG_FUNCTION = i -> 5L; - private static final IntConsumer AN_INT_CONSUMER = i -> { - }; - private static final ObjIntConsumer AN_OBJ_INT_CONSUMER = (a, b) -> { - }; - private static final IntBinaryOperator AN_INT_BINARY_OPERATOR = (a, b) -> a; - - static { - // define intermediate operations - test(IntStream.class, IntStream::distinct); - test(IntStream.class, stream -> stream.filter(AN_INT_PREDICATE)); - test(IntStream.class, stream -> stream.flatMap(AN_INT_FUNCTION)); - test(IntStream.class, stream -> stream.limit(5)); - test(IntStream.class, stream -> stream.map(AN_INT_UNARY_OPERATOR)); - test(DoubleStream.class, stream -> stream.mapToDouble(AN_INT_TO_DOUBLE_FUNCTION)); - test(Stream.class, stream -> stream.mapToObj(AN_INT_FUNCTION)); - test(LongStream.class, stream -> stream.mapToLong(AN_INT_TO_LONG_FUNCTION)); - test(IntStream.class, IntStream::parallel); - test(IntStream.class, stream -> stream.peek(AN_INT_CONSUMER)); - test(IntStream.class, IntStream::sequential); - test(IntStream.class, stream -> stream.skip(5)); - test(IntStream.class, IntStream::sorted); - test(IntStream.class, IntStream::unordered); - test(Stream.class, IntStream::boxed); - - // define terminal operations - test(stream -> stream.allMatch(AN_INT_PREDICATE), true); - test(stream -> stream.anyMatch(AN_INT_PREDICATE), true); - test(stream -> stream.collect(A_SUPPLIER, AN_OBJ_INT_CONSUMER, A_BICONSUMER), 7); - test(IntStream::count, 3L); - test(IntStream::findAny, OptionalInt.of(3)); - test(IntStream::findFirst, OptionalInt.of(3)); - test(stream -> stream.forEach(AN_INT_CONSUMER)); - test(stream -> stream.forEachOrdered(AN_INT_CONSUMER)); - test(stream -> stream.max(), OptionalInt.of(3)); - test(stream -> stream.min(), OptionalInt.of(3)); - test(stream -> stream.noneMatch(AN_INT_PREDICATE), true); - test(stream -> stream.reduce(AN_INT_BINARY_OPERATOR), OptionalInt.of(3)); - test(stream -> stream.reduce(1, AN_INT_BINARY_OPERATOR), 3); - test(IntStream::toArray, new int[1]); - test(IntStream::sum, 1); - test(IntStream::average, OptionalDouble.of(3d)); - test(IntStream::summaryStatistics, new IntSummaryStatistics()); - } - - private static void test(Consumer consumer) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return null; - } - - @Override - public T apply(IntStream stream) { - consumer.accept(stream); - return null; - } - }); - } - - private static void test(Function function, T result) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return result; - } - - @Override - public T apply(IntStream stream) { - return function.apply(stream); - } - }); - } - - private static void test(Class type, Function function) { - INTERMEDIATE_OPERATIONS.add(new IntermediateOperation() { - @Override - public Class type() { - return type; - } - - @Override - public T apply(IntStream stream) { - return function.apply(stream); - } - }); - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private IntStream delegate; - private IntStream inTest; - - @Before - public void setUp() { - delegate = mock(IntStream.class); - inTest = AutoClosingIntStream.from(delegate); - } - - @Theory - public void testIntermediateOperationReturnsNewAutoClosingStream(@FromDataPoints("intermediateOperations") IntermediateOperation intermediateOperation) { - BaseStream newDelegate = (BaseStream) mock(intermediateOperation.type()); - when(intermediateOperation.apply(delegate)).thenReturn(newDelegate); - - BaseStream result = intermediateOperation.apply(inTest); - - assertThat(result, isAutoClosing()); - verifyDelegate(result, newDelegate); - } - - @Theory - public void testTerminalOperationDelegatesToAndClosesDelegate(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - Object expectedResult = terminalOperation.result(); - if (expectedResult != null) { - when(terminalOperation.apply(delegate)).thenReturn(expectedResult); - } - - Object result = terminalOperation.apply(inTest); - - InOrder inOrder = inOrder(delegate); - assertThat(result, is(expectedResult)); - inOrder.verify(delegate).close(); - } - - @Theory - public void testTerminalOperationClosesDelegateEvenOnException(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - RuntimeException exception = new RuntimeException(); - terminalOperation.apply(doThrow(exception).when(delegate)); - - thrown.expect(is(exception)); - - try { - terminalOperation.apply(inTest); - } finally { - verify(delegate).close(); - } - } - - private Matcher isAutoClosing() { - return is(anyOf(instanceOf(AutoClosingStream.class), instanceOf(AutoClosingDoubleStream.class), instanceOf(AutoClosingIntStream.class), instanceOf(AutoClosingLongStream.class))); - } - - private void verifyDelegate(BaseStream result, BaseStream newDelegate) { - result.close(); - verify(newDelegate).close(); - } - - private interface TerminalOperation { - - T result(); - - T apply(IntStream stream); - - } - - private interface IntermediateOperation { - - Class type(); - - T apply(IntStream stream); - - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingLongStreamTest.java b/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingLongStreamTest.java deleted file mode 100644 index 02601f231..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingLongStreamTest.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.List; -import java.util.LongSummaryStatistics; -import java.util.OptionalDouble; -import java.util.OptionalLong; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.LongBinaryOperator; -import java.util.function.LongConsumer; -import java.util.function.LongFunction; -import java.util.function.LongPredicate; -import java.util.function.LongToDoubleFunction; -import java.util.function.LongToIntFunction; -import java.util.function.LongUnaryOperator; -import java.util.function.ObjLongConsumer; -import java.util.function.Supplier; -import java.util.stream.BaseStream; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.InOrder; - -@SuppressWarnings({"unchecked", "rawtypes"}) -@RunWith(Theories.class) -public class AutoClosingLongStreamTest { - - private static final LongPredicate AN_LONG_PREDICATE = any -> true; - private static final LongFunction AN_LONG_FUNCTION = i -> null; - private static final BiConsumer A_BICONSUMER = (a, b) -> { - }; - private static final Supplier A_SUPPLIER = () -> null; - - @DataPoints("intermediateOperations") - public static final List> INTERMEDIATE_OPERATIONS = new ArrayList<>(); - - @DataPoints("terminalOperations") - public static final List> TERMINAL_OPERATIONS = new ArrayList<>(); - private static final LongUnaryOperator AN_LONG_UNARY_OPERATOR = i -> 3; - private static final LongToDoubleFunction AN_LONG_TO_DOUBLE_FUNCTION = i -> 3d; - private static final LongToIntFunction AN_LONG_TO_INT_FUNCTION = i -> 5; - private static final LongConsumer AN_LONG_CONSUMER = i -> { - }; - private static final ObjLongConsumer AN_OBJ_LONG_CONSUMER = (a, b) -> { - }; - private static final LongBinaryOperator AN_LONG_BINARY_OPERATOR = (a, b) -> a; - - static { - // define intermediate operations - test(LongStream.class, LongStream::distinct); - test(LongStream.class, stream -> stream.filter(AN_LONG_PREDICATE)); - test(LongStream.class, stream -> stream.flatMap(AN_LONG_FUNCTION)); - test(LongStream.class, stream -> stream.limit(5)); - test(LongStream.class, stream -> stream.map(AN_LONG_UNARY_OPERATOR)); - test(DoubleStream.class, stream -> stream.mapToDouble(AN_LONG_TO_DOUBLE_FUNCTION)); - test(Stream.class, stream -> stream.mapToObj(AN_LONG_FUNCTION)); - test(IntStream.class, stream -> stream.mapToInt(AN_LONG_TO_INT_FUNCTION)); - test(LongStream.class, LongStream::parallel); - test(LongStream.class, stream -> stream.peek(AN_LONG_CONSUMER)); - test(LongStream.class, LongStream::sequential); - test(LongStream.class, stream -> stream.skip(5)); - test(LongStream.class, LongStream::sorted); - test(LongStream.class, LongStream::unordered); - test(Stream.class, LongStream::boxed); - - // define terminal operations - test(stream -> stream.allMatch(AN_LONG_PREDICATE), true); - test(stream -> stream.anyMatch(AN_LONG_PREDICATE), true); - test(stream -> stream.collect(A_SUPPLIER, AN_OBJ_LONG_CONSUMER, A_BICONSUMER), 7L); - test(LongStream::count, 3L); - test(LongStream::findAny, OptionalLong.of(3)); - test(LongStream::findFirst, OptionalLong.of(3)); - test(stream -> stream.forEach(AN_LONG_CONSUMER)); - test(stream -> stream.forEachOrdered(AN_LONG_CONSUMER)); - test(stream -> stream.max(), OptionalLong.of(3)); - test(stream -> stream.min(), OptionalLong.of(3)); - test(stream -> stream.noneMatch(AN_LONG_PREDICATE), true); - test(stream -> stream.reduce(AN_LONG_BINARY_OPERATOR), OptionalLong.of(3)); - test(stream -> stream.reduce(1, AN_LONG_BINARY_OPERATOR), 3L); - test(LongStream::toArray, new long[1]); - test(LongStream::sum, 1L); - test(LongStream::average, OptionalDouble.of(3d)); - test(LongStream::summaryStatistics, new LongSummaryStatistics()); - } - - private static void test(Consumer consumer) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return null; - } - - @Override - public T apply(LongStream stream) { - consumer.accept(stream); - return null; - } - }); - } - - private static void test(Function function, T result) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return result; - } - - @Override - public T apply(LongStream stream) { - return function.apply(stream); - } - }); - } - - private static void test(Class type, Function function) { - INTERMEDIATE_OPERATIONS.add(new LongermediateOperation() { - @Override - public Class type() { - return type; - } - - @Override - public T apply(LongStream stream) { - return function.apply(stream); - } - }); - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private LongStream delegate; - private LongStream inTest; - - @Before - public void setUp() { - delegate = mock(LongStream.class); - inTest = AutoClosingLongStream.from(delegate); - } - - @Theory - public void testIntermediateOperationReturnsNewAutoClosingStream(@FromDataPoints("intermediateOperations") LongermediateOperation intermediateOperation) { - BaseStream newDelegate = (BaseStream) mock(intermediateOperation.type()); - when(intermediateOperation.apply(delegate)).thenReturn(newDelegate); - - BaseStream result = intermediateOperation.apply(inTest); - - assertThat(result, isAutoClosing()); - verifyDelegate(result, newDelegate); - } - - @Theory - public void testTerminalOperationDelegatesToAndClosesDelegate(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - Object expectedResult = terminalOperation.result(); - if (expectedResult != null) { - when(terminalOperation.apply(delegate)).thenReturn(expectedResult); - } - - Object result = terminalOperation.apply(inTest); - - InOrder inOrder = inOrder(delegate); - assertThat(result, is(expectedResult)); - inOrder.verify(delegate).close(); - } - - @Theory - public void testTerminalOperationClosesDelegateEvenOnException(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - RuntimeException exception = new RuntimeException(); - terminalOperation.apply(doThrow(exception).when(delegate)); - - thrown.expect(is(exception)); - - try { - terminalOperation.apply(inTest); - } finally { - verify(delegate).close(); - } - } - - private Matcher isAutoClosing() { - return is(anyOf(instanceOf(AutoClosingStream.class), instanceOf(AutoClosingDoubleStream.class), instanceOf(AutoClosingIntStream.class), instanceOf(AutoClosingLongStream.class))); - } - - private void verifyDelegate(BaseStream result, BaseStream newDelegate) { - result.close(); - verify(newDelegate).close(); - } - - private interface TerminalOperation { - - T result(); - - T apply(LongStream stream); - - } - - private interface LongermediateOperation { - - Class type(); - - T apply(LongStream stream); - - } - -} diff --git a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingStreamTest.java b/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingStreamTest.java deleted file mode 100644 index 5f9f27fc8..000000000 --- a/main/commons/src/test/java/org/cryptomator/common/streams/AutoClosingStreamTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.cryptomator.common.streams; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.IntFunction; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.function.ToDoubleFunction; -import java.util.function.ToIntFunction; -import java.util.function.ToLongFunction; -import java.util.stream.BaseStream; -import java.util.stream.Collector; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.InOrder; - -@SuppressWarnings({"unchecked", "rawtypes"}) -@RunWith(Theories.class) -public class AutoClosingStreamTest { - - private static final Predicate A_PREDICATE = any -> true; - private static final Function A_FUNCTION = any -> null; - private static final ToDoubleFunction A_TO_DOUBLE_FUNCTION = any -> 0d; - private static final ToIntFunction A_TO_INT_FUNCTION = any -> 1; - private static final ToLongFunction A_TO_LONG_FUNCTION = any -> 1L; - private static final Consumer A_CONSUMER = any -> { - }; - private static final Comparator A_COMPARATOR = (left, right) -> 0; - private static final Collector A_COLLECTOR = mock(Collector.class); - private static final BinaryOperator A_BINARY_OPERATOR = (left, right) -> null; - private static final Object AN_OBJECT = new Object(); - private static final IntFunction AN_INT_FUNCTION = i -> null; - private static final BiConsumer A_BICONSUMER = (a, b) -> { - }; - private static final Supplier A_SUPPLIER = () -> null; - - @DataPoints("intermediateOperations") - public static final List> INTERMEDIATE_OPERATIONS = new ArrayList<>(); - - @DataPoints("terminalOperations") - public static final List> TERMINAL_OPERATIONS = new ArrayList<>(); - - static { - // define intermediate operations - test(Stream.class, Stream::distinct); - test(Stream.class, stream -> stream.filter(A_PREDICATE)); - test(Stream.class, stream -> stream.flatMap(A_FUNCTION)); - test(DoubleStream.class, stream -> stream.flatMapToDouble(A_FUNCTION)); - test(IntStream.class, stream -> stream.flatMapToInt(A_FUNCTION)); - test(LongStream.class, stream -> stream.flatMapToLong(A_FUNCTION)); - test(Stream.class, stream -> stream.limit(5)); - test(Stream.class, stream -> stream.map(A_FUNCTION)); - test(DoubleStream.class, stream -> stream.mapToDouble(A_TO_DOUBLE_FUNCTION)); - test(IntStream.class, stream -> stream.mapToInt(A_TO_INT_FUNCTION)); - test(LongStream.class, stream -> stream.mapToLong(A_TO_LONG_FUNCTION)); - test(Stream.class, Stream::parallel); - test(Stream.class, stream -> stream.peek(A_CONSUMER)); - test(Stream.class, Stream::sequential); - test(Stream.class, stream -> stream.skip(5)); - test(Stream.class, Stream::sorted); - test(Stream.class, stream -> stream.sorted(A_COMPARATOR)); - test(Stream.class, Stream::unordered); - - // define terminal operations - test(stream -> stream.allMatch(A_PREDICATE), true); - test(stream -> stream.anyMatch(A_PREDICATE), true); - test(stream -> stream.collect(A_COLLECTOR), new Object()); - test(stream -> stream.collect(A_SUPPLIER, A_BICONSUMER, A_BICONSUMER), new Object()); - test(Stream::count, 3L); - test(Stream::findAny, Optional.of(new Object())); - test(Stream::findFirst, Optional.of(new Object())); - test(stream -> stream.forEach(A_CONSUMER)); - test(stream -> stream.forEachOrdered(A_CONSUMER)); - test(stream -> stream.max(A_COMPARATOR), Optional.of(new Object())); - test(stream -> stream.min(A_COMPARATOR), Optional.of(new Object())); - test(stream -> stream.noneMatch(A_PREDICATE), true); - test(stream -> stream.reduce(A_BINARY_OPERATOR), Optional.of(new Object())); - test(stream -> stream.reduce(AN_OBJECT, A_BINARY_OPERATOR), Optional.of(new Object())); - test(stream -> stream.reduce(AN_OBJECT, A_BINARY_OPERATOR, A_BINARY_OPERATOR), Optional.of(new Object())); - test(Stream::toArray, new Object[1]); - test(stream -> stream.toArray(AN_INT_FUNCTION), new Object[1]); - } - - private static void test(Consumer consumer) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return null; - } - - @Override - public T apply(Stream stream) { - consumer.accept(stream); - return null; - } - }); - } - - private static void test(Function function, T result) { - TERMINAL_OPERATIONS.add(new TerminalOperation() { - @Override - public T result() { - return result; - } - - @Override - public T apply(Stream stream) { - return function.apply(stream); - } - }); - } - - private static void test(Class type, Function function) { - INTERMEDIATE_OPERATIONS.add(new IntermediateOperation() { - @Override - public Class type() { - return type; - } - - @Override - public T apply(Stream stream) { - return function.apply(stream); - } - }); - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Stream delegate; - private Stream inTest; - - @Before - public void setUp() { - delegate = mock(Stream.class); - inTest = AutoClosingStream.from(delegate); - } - - @Theory - public void testIntermediateOperationReturnsNewAutoClosingStream(@FromDataPoints("intermediateOperations") IntermediateOperation intermediateOperation) { - BaseStream newDelegate = (BaseStream) mock(intermediateOperation.type()); - when(intermediateOperation.apply(delegate)).thenReturn(newDelegate); - - BaseStream result = intermediateOperation.apply(inTest); - - assertThat(result, isAutoClosing()); - verifyDelegate(result, newDelegate); - } - - @Theory - public void testTerminalOperationDelegatesToAndClosesDelegate(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - Object expectedResult = terminalOperation.result(); - if (expectedResult != null) { - when(terminalOperation.apply(delegate)).thenReturn(expectedResult); - } - - Object result = terminalOperation.apply(inTest); - - InOrder inOrder = inOrder(delegate); - assertThat(result, is(expectedResult)); - inOrder.verify(delegate).close(); - } - - @Theory - public void testTerminalOperationClosesDelegateEvenOnException(@FromDataPoints("terminalOperations") TerminalOperation terminalOperation) { - RuntimeException exception = new RuntimeException(); - terminalOperation.apply(doThrow(exception).when(delegate)); - - thrown.expect(is(exception)); - - try { - terminalOperation.apply(inTest); - } finally { - verify(delegate).close(); - } - } - - private Matcher isAutoClosing() { - return is(anyOf(instanceOf(AutoClosingStream.class), instanceOf(AutoClosingDoubleStream.class), instanceOf(AutoClosingIntStream.class), instanceOf(AutoClosingLongStream.class))); - } - - private void verifyDelegate(BaseStream result, BaseStream newDelegate) { - result.close(); - verify(newDelegate).close(); - } - - private interface TerminalOperation { - - T result(); - - T apply(Stream stream); - - } - - private interface IntermediateOperation { - - Class type(); - - T apply(Stream stream); - - } - -} diff --git a/main/jacoco-report/pom.xml b/main/jacoco-report/pom.xml index 2883d4488..44511df82 100644 --- a/main/jacoco-report/pom.xml +++ b/main/jacoco-report/pom.xml @@ -5,12 +5,53 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 jacoco-report Cryptomator Code Coverage Report pom + + + + org.cryptomator + commons + + + org.cryptomator + keychain + + + org.cryptomator + ui + + + org.cryptomator + launcher + + + + org.apache.logging.log4j + * + + + + + + + com.codacy + codacy-coverage-reporter + 1.0.13 + assembly + + + * + * + + + + + @@ -26,6 +67,28 @@ + + org.codehaus.mojo + exec-maven-plugin + 1.5.0 + + + verify + + java + + + com.codacy.CodacyCoverageReporter + + -l + Java + -r + ${project.build.directory}/site/jacoco-aggregate/jacoco.xml + + + + + diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 66efa7d10..7e27fdf1f 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -3,7 +3,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 keychain System Keychain Access diff --git a/main/launcher/pom.xml b/main/launcher/pom.xml index 8496ad2a0..040edc2f6 100644 --- a/main/launcher/pom.xml +++ b/main/launcher/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 launcher Cryptomator Launcher diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java b/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java index 17b1096e5..5daa2cc91 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java @@ -17,7 +17,7 @@ public class Cryptomator { private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class); static final BlockingQueue FILE_OPEN_REQUESTS = new ArrayBlockingQueue<>(10); - public static void main(String[] args) throws IOException { + public static void main(String[] args) { LOG.info("Starting Cryptomator {} on {} {} ({})", ApplicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH); FileOpenRequestHandler fileOpenRequestHandler = new FileOpenRequestHandler(FILE_OPEN_REQUESTS); @@ -30,6 +30,8 @@ public class Cryptomator { communicator.handleLaunchArgs(args); LOG.info("Found running application instance. Shutting down."); } + } catch (IOException e) { + LOG.error("Failed to initiate inter-process communication.", e); } System.exit(0); // end remaining non-daemon threads. } diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index a021067c0..ed72e17be 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -12,7 +12,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.rmi.ConnectException; -import java.rmi.NoSuchObjectException; import java.rmi.NotBoundException; import java.rmi.Remote; import java.rmi.RemoteException; @@ -27,6 +26,8 @@ import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.io.MoreFiles; + /** * First running application on a machine opens a server socket. Further processes will connect as clients. */ @@ -113,7 +114,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt } @Override - public void close() throws IOException { + public void close() { // no-op } @@ -150,14 +151,14 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt } @Override - public void close() throws IOException { + public void close() { try { registry.unbind(RMI_NAME); UnicastRemoteObject.unexportObject(remote, true); socket.close(); LOG.debug("Server shut down."); - } catch (NotBoundException | NoSuchObjectException e) { - // ignore + } catch (NotBoundException | IOException e) { + LOG.warn("Failed to close IPC Server.", e); } } @@ -222,6 +223,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES); buf.putInt(port); buf.flip(); + MoreFiles.createParentDirectories(path); try (WritableByteChannel ch = Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { if (ch.write(buf) != Integer.BYTES) { throw new IOException("Did not write expected number of bytes."); diff --git a/main/launcher/src/test/java/org/cryptomator/launcher/InterProcessCommunicatorTest.java b/main/launcher/src/test/java/org/cryptomator/launcher/InterProcessCommunicatorTest.java index c258efb1b..63d8894f7 100644 --- a/main/launcher/src/test/java/org/cryptomator/launcher/InterProcessCommunicatorTest.java +++ b/main/launcher/src/test/java/org/cryptomator/launcher/InterProcessCommunicatorTest.java @@ -6,6 +6,7 @@ import java.nio.channels.SeekableByteChannel; import java.nio.file.FileSystem; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.spi.FileSystemProvider; import java.util.concurrent.atomic.AtomicInteger; @@ -17,6 +18,8 @@ import org.mockito.Mockito; public class InterProcessCommunicatorTest { Path portFilePath = Mockito.mock(Path.class); + Path portFileParentPath = Mockito.mock(Path.class); + BasicFileAttributes portFileParentPathAttrs = Mockito.mock(BasicFileAttributes.class); FileSystem fs = Mockito.mock(FileSystem.class); FileSystemProvider provider = Mockito.mock(FileSystemProvider.class); SeekableByteChannel portFileChannel = Mockito.mock(SeekableByteChannel.class); @@ -25,7 +28,13 @@ public class InterProcessCommunicatorTest { @Before public void setup() throws IOException { Mockito.when(portFilePath.getFileSystem()).thenReturn(fs); + Mockito.when(portFilePath.toAbsolutePath()).thenReturn(portFilePath); + Mockito.when(portFilePath.normalize()).thenReturn(portFilePath); + Mockito.when(portFilePath.getParent()).thenReturn(portFileParentPath); + Mockito.when(portFileParentPath.getFileSystem()).thenReturn(fs); Mockito.when(fs.provider()).thenReturn(provider); + Mockito.when(provider.readAttributes(portFileParentPath, BasicFileAttributes.class)).thenReturn(portFileParentPathAttrs); + Mockito.when(portFileParentPathAttrs.isDirectory()).thenReturn(false, true); // Guava's MoreFiles will check if dir exists before attempting to create them. Mockito.when(provider.newByteChannel(Mockito.eq(portFilePath), Mockito.any(), Mockito.any())).thenReturn(portFileChannel); Mockito.when(portFileChannel.read(Mockito.any())).then(invocation -> { ByteBuffer buf = invocation.getArgument(0); @@ -45,6 +54,7 @@ public class InterProcessCommunicatorTest { InterProcessCommunicationProtocol protocol = Mockito.mock(InterProcessCommunicationProtocol.class); try (InterProcessCommunicator result = InterProcessCommunicator.start(portFilePath, protocol)) { Assert.assertTrue(result.isServer()); + Mockito.verify(provider).createDirectory(portFileParentPath); Mockito.verifyZeroInteractions(protocol); result.handleLaunchArgs(new String[] {"foo"}); } @@ -57,6 +67,7 @@ public class InterProcessCommunicatorTest { InterProcessCommunicationProtocol protocol = Mockito.mock(InterProcessCommunicationProtocol.class); try (InterProcessCommunicator result = InterProcessCommunicator.start(portFilePath, protocol)) { Assert.assertTrue(result.isServer()); + Mockito.verify(provider).createDirectory(portFileParentPath); Mockito.verifyZeroInteractions(protocol); } } @@ -67,10 +78,12 @@ public class InterProcessCommunicatorTest { InterProcessCommunicationProtocol protocol = Mockito.mock(InterProcessCommunicationProtocol.class); try (InterProcessCommunicator result1 = InterProcessCommunicator.start(portFilePath, protocol)) { Assert.assertTrue(result1.isServer()); + Mockito.verify(provider, Mockito.times(1)).createDirectory(portFileParentPath); Mockito.verifyZeroInteractions(protocol); try (InterProcessCommunicator result2 = InterProcessCommunicator.start(portFilePath, null)) { Assert.assertFalse(result2.isServer()); + Mockito.verify(provider, Mockito.times(1)).createDirectory(portFileParentPath); Assert.assertNotSame(result1, result2); result2.handleLaunchArgs(new String[] {"foo"}); diff --git a/main/pom.xml b/main/pom.xml index ae88eef09..2f9e24a20 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 pom Cryptomator @@ -29,8 +29,8 @@ 1.1.1 1.2.2 - 0.5.1 - 1.0.1 + 0.6.0 + 1.0.2 2.8.1 1.7.25 4.12 @@ -269,10 +269,18 @@ - test-coverage + coverage jacoco-report + + + + org.jacoco + jacoco-maven-plugin + + + diff --git a/main/uber-jar/pom.xml b/main/uber-jar/pom.xml index 2fc2e118b..1e07be7df 100644 --- a/main/uber-jar/pom.xml +++ b/main/uber-jar/pom.xml @@ -5,7 +5,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 uber-jar Single über jar with all dependencies diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 9de070ae8..4f578d279 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 1.3.0-rc3 + 1.3.0-rc4 ui Cryptomator GUI @@ -99,16 +99,9 @@ - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.logging.log4j - log4j-jul + org.slf4j + slf4j-simple + test diff --git a/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java b/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java index 0aebd795f..78fa03ce4 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java +++ b/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -37,7 +37,7 @@ import org.cryptomator.common.settings.Settings; import org.cryptomator.jni.JniException; import org.cryptomator.jni.MacApplicationUiState; import org.cryptomator.jni.MacFunctions; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -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 { diff --git a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java index cecf183f1..e6c31e0ce 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -24,10 +24,7 @@ import org.cryptomator.jni.JniModule; import org.cryptomator.keychain.KeychainModule; import org.cryptomator.ui.controllers.ViewControllerModule; import org.cryptomator.ui.model.VaultComponent; -import org.cryptomator.ui.util.DeferredCloser; import org.fxmisc.easybind.EasyBind; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import dagger.Module; import dagger.Provides; @@ -36,22 +33,6 @@ import javafx.beans.binding.Binding; @Module(includes = {ViewControllerModule.class, CommonsModule.class, KeychainModule.class, JniModule.class}, subcomponents = {VaultComponent.class}) public class UiModule { - private static final Logger LOG = LoggerFactory.getLogger(UiModule.class); - - @Provides - @Singleton - DeferredCloser provideDeferredCloser(@Named("shutdownTaskScheduler") Consumer shutdownTaskScheduler) { - DeferredCloser closer = new DeferredCloser(); - shutdownTaskScheduler.accept(() -> { - try { - closer.close(); - } catch (Exception e) { - LOG.error("Error during shutdown.", e); - } - }); - return closer; - } - @Provides @Singleton Settings provideSettings(SettingsProvider settingsProvider) { @@ -60,8 +41,10 @@ public class UiModule { @Provides @Singleton - ExecutorService provideExecutorService(DeferredCloser closer) { - return closer.closeLater(Executors.newCachedThreadPool(), ExecutorService::shutdown).get().orElseThrow(IllegalStateException::new); + ExecutorService provideExecutorService(@Named("shutdownTaskScheduler") Consumer shutdownTaskScheduler) { + ExecutorService executorService = Executors.newCachedThreadPool(); + shutdownTaskScheduler.accept(executorService::shutdown); + return executorService; } @Provides diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java index 45b652ce5..d51b6cf2a 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -20,8 +20,8 @@ import javax.inject.Singleton; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.ui.controls.SecPasswordField; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.PasswordStrengthUtil; import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java index 5a21eba91..c4d439077 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -19,8 +19,8 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.cryptomator.ui.controls.SecPasswordField; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.PasswordStrengthUtil; import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java index 80223b92f..ba15b47e1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -26,16 +26,16 @@ import javax.inject.Named; import javax.inject.Singleton; import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.ui.ExitUtil; import org.cryptomator.ui.controls.DirectoryListCell; +import org.cryptomator.ui.l10n.Localization; +import org.cryptomator.ui.model.AutoUnlocker; import org.cryptomator.ui.model.UpgradeStrategies; import org.cryptomator.ui.model.UpgradeStrategy; import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.model.VaultFactory; import org.cryptomator.ui.model.VaultList; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.DialogBuilderUtil; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -51,6 +51,8 @@ import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.geometry.Side; @@ -83,11 +85,11 @@ public class MainController implements ViewController { private final Localization localization; private final ExecutorService executorService; private final BlockingQueue fileOpenRequests; - private final Settings settings; private final VaultFactory vaultFactoy; private final ViewControllerLoader viewControllerLoader; private final ObjectProperty activeController = new SimpleObjectProperty<>(); - private final VaultList vaults; + private final ObservableList vaults; + private final BooleanBinding areAllVaultsLocked; private final ObjectProperty selectedVault = new SimpleObjectProperty<>(); private final BooleanExpression isSelectedVaultUnlocked = BooleanExpression.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false)); private final BooleanExpression isSelectedVaultValid = BooleanExpression.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false)); @@ -100,13 +102,12 @@ public class MainController implements ViewController { @Inject public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("fileOpenRequests") BlockingQueue fileOpenRequests, ExitUtil exitUtil, Localization localization, - Settings settings, VaultFactory vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, VaultList vaults) { + VaultFactory vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, VaultList vaults, AutoUnlocker autoUnlocker) { this.mainWindow = mainWindow; this.executorService = executorService; this.fileOpenRequests = fileOpenRequests; this.exitUtil = exitUtil; this.localization = localization; - this.settings = settings; this.vaultFactoy = vaultFactoy; this.viewControllerLoader = viewControllerLoader; this.vaults = vaults; @@ -114,6 +115,10 @@ public class MainController implements ViewController { // derived bindings: this.isShowingSettings = Bindings.equal(SettingsController.class, EasyBind.monadic(activeController).map(ViewController::getClass)); this.upgradeStrategyForSelectedVault = EasyBind.monadic(selectedVault).map(upgradeStrategies::getUpgradeStrategy); + this.areAllVaultsLocked = Bindings.isEmpty(FXCollections.observableList(vaults, Vault::observables).filtered(Vault::isUnlocked)); + + EasyBind.subscribe(areAllVaultsLocked, Platform::setImplicitExit); + autoUnlocker.unlockAllSilently(); } @FXML @@ -184,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); @@ -259,7 +269,7 @@ public class MainController implements ViewController { final List files = fileChooser.showOpenMultipleDialog(mainWindow); if (files != null) { for (final File file : files) { - addVault(file.toPath(), false); + addVault(file.toPath(), true); } } } @@ -281,7 +291,7 @@ public class MainController implements ViewController { } final Vault vault = vaults.stream().filter(v -> v.getPath().equals(vaultPath)).findAny().orElseGet(() -> { - VaultSettings vaultSettings = VaultSettings.withRandomId(settings); + VaultSettings vaultSettings = VaultSettings.withRandomId(); vaultSettings.path().set(vaultPath); return vaultFactoy.get(vaultSettings); }); @@ -399,7 +409,6 @@ public class MainController implements ViewController { } public void didUnlock(Vault vault) { - Platform.setImplicitExit(false); if (vault.equals(selectedVault.getValue())) { this.showUnlockedView(vault); } @@ -417,9 +426,6 @@ public class MainController implements ViewController { public void didLock(UnlockedController ctrl) { unlockedVaults.remove(ctrl.getVault()); showUnlockView(); - if (!vaults.stream().anyMatch(Vault::isUnlocked)) { - Platform.setImplicitExit(true); - } } private void showChangePasswordView() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java index a2984623b..44e18e2c7 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -14,10 +14,12 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.settings.Settings; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; + +import com.google.common.base.CharMatcher; +import com.google.common.base.Strings; import javafx.beans.binding.Bindings; import javafx.event.ActionEvent; @@ -34,6 +36,8 @@ import javafx.scene.layout.VBox; @Singleton public class SettingsController implements ViewController { + private static final CharMatcher DIGITS_MATCHER = CharMatcher.inRange('0', '9'); + private final Localization localization; private final Settings settings; private final Optional applicationVersion; @@ -130,11 +134,7 @@ public class SettingsController implements ViewController { } private void filterNumericKeyEvents(KeyEvent t) { - if (t.getCharacter() == null || t.getCharacter().length() == 0) { - return; - } - char c = CharUtils.toChar(t.getCharacter()); - if (!(CharUtils.isAsciiNumeric(c) || c == '_')) { + if (!Strings.isNullOrEmpty(t.getCharacter()) && !DIGITS_MATCHER.matchesAllOf(t.getCharacter())) { t.consume(); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java index a3b624c82..a0554c3e6 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -17,20 +17,26 @@ import javax.inject.Inject; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.frontend.webdav.ServerLifecycleException; import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException; import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.ui.controls.SecPasswordField; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.model.WindowsDriveLetters; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.AsyncTaskService; import org.cryptomator.ui.util.DialogBuilderUtil; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.CharMatcher; +import com.google.common.base.Strings; + import javafx.application.Application; import javafx.application.Platform; import javafx.beans.value.ChangeListener; @@ -55,6 +61,11 @@ import javafx.util.StringConverter; public class UnlockController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class); + private static final CharMatcher ALPHA_NUMERIC_MATCHER = CharMatcher.inRange('a', 'z') // + .or(CharMatcher.inRange('A', 'Z')) // + .or(CharMatcher.inRange('0', '9')) // + .or(CharMatcher.is('_')) // + .precomputed(); private final Application app; private final Localization localization; @@ -64,6 +75,7 @@ public class UnlockController implements ViewController { private final Optional keychainAccess; private Vault vault; private Optional listener = Optional.empty(); + private Subscription vaultSubs = Subscription.EMPTY; @Inject public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, WindowsDriveLetters driveLetters, Optional keychainAccess) { @@ -116,6 +128,9 @@ public class UnlockController implements ViewController { @FXML private GridPane root; + @FXML + private CheckBox unlockAfterStartup; + @Override public void initialize() { advancedOptions.managedProperty().bind(advancedOptions.visibleProperty()); @@ -125,6 +140,7 @@ public class UnlockController implements ViewController { mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents); mountName.textProperty().addListener(this::mountNameDidChange); savePassword.setDisable(!keychainAccess.isPresent()); + unlockAfterStartup.disableProperty().bind(savePassword.disabledProperty().or(savePassword.selectedProperty().not())); if (SystemUtils.IS_OS_WINDOWS) { winDriveLetter.setConverter(new WinDriveLetterLabelConverter()); } else { @@ -141,18 +157,17 @@ public class UnlockController implements ViewController { } void setVault(Vault vault) { - // TODO overheadhunter refactor - if (this.vault != null) { - this.vault.getVaultSettings().mountAfterUnlock().unbind(); - this.vault.getVaultSettings().revealAfterMount().unbind(); - } + vaultSubs.unsubscribe(); + vaultSubs = Subscription.EMPTY; + // trigger "default" change to refresh key bindings: unlockButton.setDefaultButton(false); unlockButton.setDefaultButton(true); - if (vault.equals(this.vault)) { + if (Objects.equals(this.vault, Objects.requireNonNull(vault))) { return; } - this.vault = Objects.requireNonNull(vault); + assert vault != null; + this.vault = vault; passwordField.swipe(); advancedOptions.setVisible(false); advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show")); @@ -182,10 +197,14 @@ public class UnlockController implements ViewController { Arrays.fill(storedPw, ' '); } } - mountAfterUnlock.setSelected(this.vault.getVaultSettings().mountAfterUnlock().get()); - revealAfterMount.setSelected(this.vault.getVaultSettings().revealAfterMount().get()); - this.vault.getVaultSettings().mountAfterUnlock().bind(mountAfterUnlock.selectedProperty()); - this.vault.getVaultSettings().revealAfterMount().bind(revealAfterMount.selectedProperty()); + VaultSettings settings = vault.getVaultSettings(); + unlockAfterStartup.setSelected(savePassword.isSelected() && settings.unlockAfterStartup().get()); + mountAfterUnlock.setSelected(settings.mountAfterUnlock().get()); + revealAfterMount.setSelected(settings.revealAfterMount().get()); + + vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), settings.unlockAfterStartup()::set)); + vaultSubs = vaultSubs.and(EasyBind.subscribe(mountAfterUnlock.selectedProperty(), settings.mountAfterUnlock()::set)); + vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), settings.revealAfterMount()::set)); } // **************************************** @@ -212,11 +231,7 @@ public class UnlockController implements ViewController { } private void filterAlphanumericKeyEvents(KeyEvent t) { - if (t.getCharacter() == null || t.getCharacter().length() == 0) { - return; - } - char c = CharUtils.toChar(t.getCharacter()); - if (!(CharUtils.isAsciiAlphanumeric(c) || c == '_')) { + if (!Strings.isNullOrEmpty(t.getCharacter()) && !ALPHA_NUMERIC_MATCHER.matchesAllOf(t.getCharacter())) { t.consume(); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java index c0efa6fdf..52f70da77 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -8,14 +8,19 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; +import static java.lang.String.format; + import java.util.Optional; import javax.inject.Inject; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.AsyncTaskService; +import org.cryptomator.ui.util.DialogBuilderUtil; import org.fxmisc.easybind.EasyBind; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javafx.animation.Animation; import javafx.animation.KeyFrame; @@ -31,6 +36,8 @@ import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Series; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; @@ -43,6 +50,8 @@ import javafx.util.Duration; public class UnlockedController implements ViewController { + private static final Logger LOG = LoggerFactory.getLogger(UnlockedController.class); + private static final int IO_SAMPLING_STEPS = 100; private static final double IO_SAMPLING_INTERVAL = 0.25; @@ -109,16 +118,63 @@ public class UnlockedController implements ViewController { @FXML private void didClickLockVault(ActionEvent event) { + regularLockVault(); + } + + private void regularLockVault() { asyncTaskService.asyncTaskOf(() -> { vault.get().unmount(); vault.get().lock(); }).onSuccess(() -> { listener.ifPresent(listener -> listener.didLock(this)); - }).onError(Exception.class, () -> { - messageLabel.setText(localization.getString("unlocked.label.unmountFailed")); + LOG.trace("Regular lock succeeded"); + }).onError(Exception.class, e -> { + onRegularLockVaultFailed(e); }).run(); } + private void forcedLockVault() { + asyncTaskService.asyncTaskOf(() -> { + vault.get().unmountForced(); + vault.get().lock(); + }).onSuccess(() -> { + listener.ifPresent(listener -> listener.didLock(this)); + LOG.trace("Forced lock succeeded"); + }).onError(Exception.class, e -> { + onForcedLockVaultFailed(e); + }).run(); + } + + private void onRegularLockVaultFailed(Exception e) { + if (vault.get().supportsForcedUnmount()) { + LOG.trace("Regular unmount failed", e); + Alert confirmDialog = DialogBuilderUtil.buildYesNoDialog( // + format(localization.getString("unlocked.lock.force.confirmation.title"), vault.get().name().getValue()), // + localization.getString("unlocked.lock.force.confirmation.header"), // + localization.getString("unlocked.lock.force.confirmation.content"), // + ButtonType.NO); + + Optional choice = confirmDialog.showAndWait(); + if (ButtonType.YES.equals(choice.get())) { + forcedLockVault(); + } else { + LOG.trace("Unmount cancelled", e); + } + } else { + LOG.error("Regular unmount failed", e); + showUnmountFailedMessage(); + } + } + + private void onForcedLockVaultFailed(Exception e) { + LOG.error("Forced unmount failed", e); + showUnmountFailedMessage(); + } + + private void showUnmountFailedMessage() { + messageLabel.setText(localization.getString("unlocked.label.unmountFailed")); + } + @FXML private void didClickMoreOptions(ActionEvent event) { if (moreOptionsMenu.isShowing()) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java index 63eacdbda..aafd46085 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java @@ -11,11 +11,11 @@ import java.util.Optional; import javax.inject.Inject; import org.cryptomator.ui.controls.SecPasswordField; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.UpgradeStrategies; import org.cryptomator.ui.model.UpgradeStrategy; import org.cryptomator.ui.model.UpgradeStrategy.UpgradeFailedException; import org.cryptomator.ui.model.Vault; -import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.util.AsyncTaskService; import org.fxmisc.easybind.EasyBind; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java index ba6a641b7..1d27a0598 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewController.java @@ -1,3 +1,8 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ package org.cryptomator.ui.controllers; import java.net.URL; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java index 6c47cee49..72af006ea 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerKey.java @@ -1,3 +1,8 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ package org.cryptomator.ui.controllers; import static java.lang.annotation.ElementType.METHOD; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java index 867caea63..b345dafdc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerLoader.java @@ -1,3 +1,8 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ package org.cryptomator.ui.controllers; import java.io.IOException; @@ -9,7 +14,7 @@ import javax.inject.Inject; import javax.inject.Provider; import javax.inject.Singleton; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import javafx.fxml.FXMLLoader; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java index b8f4a019f..f688f95cf 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ViewControllerModule.java @@ -1,3 +1,8 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ package org.cryptomator.ui.controllers; import dagger.Module; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java index 8698b3d09..da5c9c572 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -30,7 +30,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.cryptomator.common.settings.Settings; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.util.AsyncTaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/DirectoryListCell.java b/main/ui/src/main/java/org/cryptomator/ui/controls/DirectoryListCell.java index 74f98177a..2c549509c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/DirectoryListCell.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/DirectoryListCell.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -20,9 +20,12 @@ import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; public class DirectoryListCell extends DraggableListCell { + private static final Color UNLOCKED_ICON_COLOR = new Color(0.901, 0.494, 0.133, 1.0); private final Label statusText = new Label(); private final Label nameText = new Label(); private final Label pathText = new Label(); @@ -45,7 +48,7 @@ public class DirectoryListCell extends DraggableListCell { MonadicBinding optionalItemIsUnlocked = EasyBind.monadic(itemProperty()).flatMap(Vault::unlockedProperty); statusText.textProperty().bind(optionalItemIsUnlocked.map(this::getStatusIconText)); - statusText.textFillProperty().bind(this.textFillProperty()); + statusText.textFillProperty().bind(EasyBind.combine(optionalItemIsUnlocked, textFillProperty(), this::getStatusIconColor)); statusText.setMinSize(16.0, 16.0); statusText.setAlignment(Pos.CENTER); statusText.getStyleClass().add("fontawesome"); @@ -67,6 +70,14 @@ public class DirectoryListCell extends DraggableListCell { } } + private Paint getStatusIconColor(Boolean unlockedOrNull, Paint lockedValue) { + if (Boolean.TRUE.equals(unlockedOrNull)) { + return UNLOCKED_ICON_COLOR; + } else { + return lockedValue; + } + } + public void setVaultContextMenu(ContextMenu contextMenu) { this.vaultContextMenu = contextMenu; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java index 6ab34a3b1..65e32fc1d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java b/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java index c7c6fc8fa..01dfbf6f5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Sebastian Stenzel + * Copyright (c) 2014, 2017 Sebastian Stenzel * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * diff --git a/main/ui/src/main/java/org/cryptomator/ui/settings/Localization.java b/main/ui/src/main/java/org/cryptomator/ui/l10n/Localization.java similarity index 98% rename from main/ui/src/main/java/org/cryptomator/ui/settings/Localization.java rename to main/ui/src/main/java/org/cryptomator/ui/l10n/Localization.java index 99f4e7a55..e5876a5ef 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/settings/Localization.java +++ b/main/ui/src/main/java/org/cryptomator/ui/l10n/Localization.java @@ -3,7 +3,7 @@ * All rights reserved. This program and the accompanying materials * are made available under the terms of the accompanying LICENSE file. *******************************************************************************/ -package org.cryptomator.ui.settings; +package org.cryptomator.ui.l10n; import java.io.IOException; import java.io.InputStream; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/AutoUnlocker.java b/main/ui/src/main/java/org/cryptomator/ui/model/AutoUnlocker.java new file mode 100644 index 000000000..124d1f903 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/AutoUnlocker.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ +package org.cryptomator.ui.model; + +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.stream.Collectors; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.cryptomator.cryptolib.api.CryptoException; +import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException; +import org.cryptomator.keychain.KeychainAccess; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class AutoUnlocker { + + private static final Logger LOG = LoggerFactory.getLogger(AutoUnlocker.class); + private static final int NAP_TIME_MILLIS = 500; + + private final Optional keychainAccess; + private final VaultList vaults; + private final ExecutorService executor; + + @Inject + public AutoUnlocker(Optional keychainAccess, VaultList vaults, ExecutorService executor) { + this.keychainAccess = keychainAccess; + this.vaults = vaults; + this.executor = executor; + } + + public void unlockAllSilently() { + Collection vaultsToUnlock = vaults.stream().filter(this::shouldUnlockAfterStartup).collect(Collectors.toList()); + if (keychainAccess.isPresent() && !vaultsToUnlock.isEmpty()) { + executor.submit(() -> unlockAll(vaultsToUnlock)); + } + } + + private boolean shouldUnlockAfterStartup(Vault vault) { + return vault.getVaultSettings().unlockAfterStartup().get(); + } + + private void unlockAll(Collection vaults) { + try { + Iterator iterator = vaults.iterator(); + assert iterator.hasNext() : "vaults must not be empty"; + unlockSilently(iterator.next()); + while (iterator.hasNext()) { + Thread.sleep(NAP_TIME_MILLIS); + unlockSilently(iterator.next()); + } + } catch (InterruptedException e) { + LOG.warn("Auto unlock thread interrupted."); + Thread.currentThread().interrupt(); + } + } + + private void unlockSilently(Vault vault) { + char[] storedPw = keychainAccess.get().loadPassphrase(vault.getId()); + if (storedPw == null) { + LOG.warn("No passphrase stored in keychain for vault registered for auto unlocking: {}", vault.getPath()); + } + try { + vault.unlock(CharBuffer.wrap(storedPw)); + mountSilently(vault); + } catch (CryptoException e) { + LOG.error("Auto unlock failed.", e); + } finally { + Arrays.fill(storedPw, ' '); + } + } + + private void mountSilently(Vault unlockedVault) { + if (!unlockedVault.getVaultSettings().mountAfterUnlock().get()) { + return; + } + try { + unlockedVault.mount(); + revealSilently(unlockedVault); + } catch (CommandFailedException e) { + LOG.error("Auto unlock succeded, but mounting the drive failed.", e); + } + } + + private void revealSilently(Vault mountedVault) { + if (!mountedVault.getVaultSettings().revealAfterMount().get()) { + return; + } + try { + mountedVault.reveal(); + } catch (CommandFailedException e) { + LOG.error("Auto unlock succeded, but revealing the drive failed.", e); + } + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java index 40105140b..5f7ccf333 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java @@ -18,7 +18,7 @@ import org.cryptomator.cryptolib.api.CryptorProvider; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.KeyFile; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java index 9bbc5f2d2..1fa8ff306 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java @@ -15,7 +15,7 @@ import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; import org.cryptomator.cryptolib.Cryptors; import org.cryptomator.cryptolib.api.Cryptor; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index 8e12c8fd7..3dd4b6010 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -28,7 +28,7 @@ import org.apache.commons.lang3.StringUtils; import org.cryptomator.cryptolib.Cryptors; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.common.MessageDigestSupplier; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java index ba2207ebc..ae26f75da 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java @@ -24,7 +24,7 @@ import javax.inject.Singleton; import org.cryptomator.cryptolib.Cryptors; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.FileHeader; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 4e84a5f39..f963c03f6 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -18,12 +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.LazyInitializer; +import org.cryptomator.common.Optionals; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; @@ -35,14 +37,15 @@ 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; import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javafx.application.Platform; +import javafx.beans.Observable; import javafx.beans.binding.Binding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -56,7 +59,6 @@ public class Vault { private final Settings settings; private final VaultSettings vaultSettings; private final WebDavServer server; - private final DeferredCloser closer; private final BooleanProperty unlocked = new SimpleBooleanProperty(); private final BooleanProperty mounted = new SimpleBooleanProperty(); private final AtomicReference cryptoFileSystem = new AtomicReference<>(); @@ -65,18 +67,17 @@ public class Vault { private Mount mount; @Inject - Vault(Settings settings, VaultSettings vaultSettings, WebDavServer server, DeferredCloser closer) { + Vault(Settings settings, VaultSettings vaultSettings, WebDavServer server) { this.settings = settings; this.vaultSettings = vaultSettings; this.server = server; - this.closer = closer; } // ****************************************************************************** // Commands // ********************************************************************************/ - private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws IOException { + private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws IOException, CryptoException { return LazyInitializer.initializeLazily(cryptoFileSystem, () -> createCryptoFileSystem(passphrase), IOException.class); } @@ -85,9 +86,7 @@ public class Vault { .withPassphrase(passphrase) // .withMasterkeyFilename(MASTERKEY_FILENAME) // .build(); - CryptoFileSystem fs = CryptoFileSystemProvider.newFileSystem(getPath(), fsProps); - closer.closeLater(fs); - return fs; + return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps); } public void create(CharSequence passphrase) throws IOException { @@ -99,7 +98,7 @@ public class Vault { } } if (!isValidVaultDirectory()) { - getCryptoFileSystem(passphrase); // implicitly creates a non-existing vault + createCryptoFileSystem(passphrase).close(); // implicitly creates a non-existing vault } else { throw new FileAlreadyExistsException(getPath().toString()); } @@ -125,7 +124,7 @@ public class Vault { } } - public synchronized void mount() { + public synchronized void mount() throws CommandFailedException { if (servlet == null) { throw new IllegalStateException("Mounting requires unlocked WebDAV servlet."); } @@ -135,25 +134,33 @@ public class Vault { .withPreferredGvfsScheme(settings.preferredGvfsScheme().get()) // .build(); - try { - mount = servlet.mount(mountParams); - Platform.runLater(() -> { - mounted.set(true); - }); - } catch (CommandFailedException e) { - LOG.error("Unable to mount filesystem", e); - } + mount = servlet.mount(mountParams); + Platform.runLater(() -> { + mounted.set(true); + }); } - public synchronized void unmount() throws Exception { + public synchronized void unmount() throws CommandFailedException { + unmount(Function.identity()); + } + + public synchronized void unmountForced() throws CommandFailedException { + unmount(Optionals.unwrap(Mount::forced)); + } + + private synchronized void unmount(Function unmountOperationChooser) throws CommandFailedException { if (mount != null) { - mount.unmount(); + unmountOperationChooser.apply(mount).unmount(); } Platform.runLater(() -> { mounted.set(false); }); } + public boolean supportsForcedUnmount() { + return mount != null && mount.forced().isPresent(); + } + public synchronized void lock() throws Exception { if (servlet != null) { servlet.stop(); @@ -167,6 +174,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(); @@ -177,6 +208,10 @@ public class Vault { // Getter/Setter // *******************************************************************************/ + public Observable[] observables() { + return new Observable[] {unlocked, mounted}; + } + public VaultSettings getVaultSettings() { return vaultSettings; } 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 index 7b4b553e2..da9448f2c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/VaultFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -15,12 +15,11 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.cryptomator.common.settings.VaultSettings; -import org.cryptomator.ui.model.VaultComponent.Builder; @Singleton public class VaultFactory { - private final Builder vaultComponentBuilder; + private final VaultComponent.Builder vaultComponentBuilder; private final ConcurrentMap vaults = new ConcurrentHashMap<>(); @Inject diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/VaultList.java b/main/ui/src/main/java/org/cryptomator/ui/model/VaultList.java index 519fea90f..f2c9718fc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/VaultList.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/VaultList.java @@ -5,8 +5,8 @@ *******************************************************************************/ package org.cryptomator.ui.model; -import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; import javax.inject.Inject; import javax.inject.Singleton; @@ -14,7 +14,9 @@ import javax.inject.Singleton; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; -import javafx.collections.ListChangeListener.Change; +import com.google.common.collect.Lists; + +import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.transformation.TransformationList; @@ -59,15 +61,15 @@ public class VaultList extends TransformationList { } @Override - protected void sourceChanged(Change c) { + protected void sourceChanged(ListChangeListener.Change c) { this.fireChange(new VaultListChange(c)); } - private class VaultListChange extends Change { + private class VaultListChange extends ListChangeListener.Change { - private final Change delegate; + private final ListChangeListener.Change delegate; - public VaultListChange(Change delegate) { + public VaultListChange(ListChangeListener.Change delegate) { super(VaultList.this); this.delegate = delegate; } @@ -77,6 +79,11 @@ public class VaultList extends TransformationList { return delegate.next(); } + @Override + public boolean wasUpdated() { + return delegate.wasUpdated(); + } + @Override public void reset() { delegate.reset(); @@ -94,27 +101,28 @@ public class VaultList extends TransformationList { @Override public List getRemoved() { - List removed = new ArrayList<>(); - for (VaultSettings s : delegate.getRemoved()) { - removed.add(vaultFactory.get(s)); - } - return removed; + return Lists.transform(delegate.getRemoved(), vaultFactory::get); + } + + @Override + public boolean wasPermutated() { + return delegate.wasPermutated(); } @Override protected int[] getPermutation() { if (delegate.wasPermutated()) { - int len = getTo() - getFrom(); - int[] permutations = new int[len]; - for (int i = 0; i < len; i++) { - permutations[i] = getPermutation(i); - } - return permutations; + return IntStream.range(getFrom(), getTo()).map(delegate::getPermutation).toArray(); } else { return new int[0]; } } + @Override + public String toString() { + return delegate.toString(); + } + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java b/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java index 8eaf198d5..391d3ae77 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java @@ -49,7 +49,7 @@ public class AsyncTaskService { private ConsumerThrowingException successHandler = value -> { }; - private List> errorHandlers = new ArrayList<>(); + private final List> errorHandlers = new ArrayList<>(); private RunnableThrowingException finallyHandler = () -> { }; diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/DeferredClosable.java b/main/ui/src/main/java/org/cryptomator/ui/util/DeferredClosable.java deleted file mode 100644 index fa8c415ab..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/util/DeferredClosable.java +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014, 2016 cryptomator.org - * This file is licensed under the terms of the MIT license. - * See the LICENSE.txt file for more info. - * - * Contributors: - * Tillmann Gaida - initial implementation - ******************************************************************************/ -package org.cryptomator.ui.util; - -import java.util.Optional; - -/** - * Wrapper around an object, which should be closed later - explicitly or by a - * {@link DeferredCloser}. The wrapped object can be accessed as long as the - * resource has not been closed. - * - * @author Tillmann Gaida - * - * @param - * any type - */ -public interface DeferredClosable extends AutoCloseable { - /** - * Returns the wrapped Object. - * - * @return empty if the object has been closed. - */ - public Optional get(); - - /** - * @return an empty object. - */ - public static DeferredClosable empty() { - return DeferredCloser.empty(); - } -} \ No newline at end of file diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/DeferredCloser.java b/main/ui/src/main/java/org/cryptomator/ui/util/DeferredCloser.java deleted file mode 100644 index f2de9324f..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/util/DeferredCloser.java +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014, 2016 cryptomator.org - * This file is licensed under the terms of the MIT license. - * See the LICENSE.txt file for more info. - * - * Contributors: - * Tillmann Gaida - initial implementation - ******************************************************************************/ -package org.cryptomator.ui.util; - -import java.util.Iterator; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicLong; - -import org.cryptomator.common.ConsumerThrowingException; - -import com.google.common.annotations.VisibleForTesting; - -/** - *

- * Tries to bring open-close symmetry in contexts where the resource outlives - * the current scope by introducing a manager, which closes the resources if - * they haven't been closed before. - *

- * - *

- * If you have a {@link DeferredCloser} instance present, call - * {@link #closeLater(Object, ConsumerThrowingException)} immediately after you have opened the - * resource and return a resource handle. If {@link #close()} is called, the - * resource will be closed. Calling {@link DeferredClosable#close()} on the resource - * handle will also close the resource and prevent a second closing by - * {@link #close()}. - *

- * - * @author Tillmann Gaida - */ -public class DeferredCloser implements AutoCloseable { - - @VisibleForTesting - final Map> cleanups = new ConcurrentSkipListMap<>(); - - @VisibleForTesting - final AtomicLong counter = new AtomicLong(); - - private class ManagedResource implements DeferredClosable { - - private final long number = counter.incrementAndGet(); - private final T object; - private final ConsumerThrowingException closer; - private boolean closed = false; - - public ManagedResource(T object, ConsumerThrowingException closer) { - super(); - this.object = Objects.requireNonNull(object); - this.closer = Objects.requireNonNull(closer); - } - - @Override - public synchronized void close() throws Exception { - closer.accept(object); - cleanups.remove(number); - closed = true; - } - - @Override - public Optional get() throws IllegalStateException { - if (closed) { - return Optional.empty(); - } else { - return Optional.of(object); - } - } - } - - /** - * Closes all added objects which have not been closed before and releases references. - */ - @Override - public void close() throws ExecutionException { - ExecutionException exception = null; - for (Iterator> iterator = cleanups.values().iterator(); iterator.hasNext();) { - final ManagedResource closableProvider = iterator.next(); - try { - closableProvider.close(); - iterator.remove(); - } catch (Exception e) { - if (exception == null) { - exception = new ExecutionException(e); - } else { - exception.addSuppressed(e); - } - } - } - if (exception != null) { - throw exception; - } - } - - public DeferredClosable closeLater(T object, ConsumerThrowingException closer) { - Objects.requireNonNull(object); - Objects.requireNonNull(closer); - final ManagedResource resource = new ManagedResource(object, closer); - cleanups.put(resource.number, resource); - return resource; - } - - public DeferredClosable closeLater(T object) { - Objects.requireNonNull(object); - final ManagedResource resource = new ManagedResource(object, AutoCloseable::close); - cleanups.put(resource.number, resource); - return resource; - } - - private static final EmptyResource EMPTY_RESOURCE = new EmptyResource<>(); - - @SuppressWarnings("unchecked") - public static DeferredClosable empty() { - return (DeferredClosable) EMPTY_RESOURCE; - } - - static class EmptyResource implements DeferredClosable { - @Override - public Optional get() { - return Optional.empty(); - } - - @Override - public void close() { - - } - } -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java b/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java index e9f1b99fe..11943d1a8 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -34,11 +34,15 @@ public class DialogBuilderUtil { return buildDialog(title, header, content, Alert.AlertType.CONFIRMATION, defaultButton); } - private static Alert buildDialog(String title, String header, String content, Alert.AlertType type, ButtonType defaultButton) { + public static Alert buildYesNoDialog(String title, String header, String content, ButtonType defaultButton) { + return buildDialog(title, header, content, Alert.AlertType.CONFIRMATION, defaultButton, ButtonType.YES, ButtonType.NO); + } + + private static Alert buildDialog(String title, String header, String content, Alert.AlertType type, ButtonType defaultButton, ButtonType... buttons) { Text contentText = new Text(content); contentText.setWrappingWidth(360.0); - Alert alert = new Alert(type); + Alert alert = new Alert(type, content, buttons); alert.setTitle(title); alert.setHeaderText(header); alert.getDialogPane().setContent(contentText); diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java index 300cee4e1..17f1f54f8 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Sebastian Stenzel and others. + * Copyright (c) 2016, 2017 Sebastian Stenzel and others. * This file is licensed under the terms of the MIT license. * See the LICENSE.txt file for more info. * @@ -15,7 +15,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; -import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.l10n.Localization; import com.nulabinc.zxcvbn.Zxcvbn; diff --git a/main/ui/src/main/resources/fxml/settings.fxml b/main/ui/src/main/resources/fxml/settings.fxml index 65199e284..4f7fc3bfe 100644 --- a/main/ui/src/main/resources/fxml/settings.fxml +++ b/main/ui/src/main/resources/fxml/settings.fxml @@ -53,7 +53,7 @@ -