JaniruTEC
2020-08-20 23:58:21 +02:00
parent 4cd43a2b1c
commit 5dac594cc9
6 changed files with 89 additions and 80 deletions

View File

@@ -8,6 +8,8 @@ import java.util.Optional;
public class AvailableDriveLetterChooser implements MountPointChooser {
private static final int POSITION = 200;
private final WindowsDriveLetters windowsDriveLetters;
public AvailableDriveLetterChooser(WindowsDriveLetters windowsDriveLetters) {
@@ -23,4 +25,9 @@ public class AvailableDriveLetterChooser implements MountPointChooser {
public Optional<Path> chooseMountPoint() {
return this.windowsDriveLetters.getAvailableDriveLetterPath();
}
@Override
public int getPosition() {
return POSITION;
}
}

View File

@@ -9,6 +9,8 @@ import java.util.Optional;
public class CustomDriveLetterChooser implements MountPointChooser {
public static final int POSITION = 100;
private final Vault vault;
public CustomDriveLetterChooser(Vault vault) {
@@ -24,4 +26,9 @@ public class CustomDriveLetterChooser implements MountPointChooser {
public Optional<Path> chooseMountPoint() {
return this.vault.getVaultSettings().getWinDriveLetter().map(letter -> letter.charAt(0) + ":\\").map(Paths::get);
}
@Override
public int getPosition() {
return POSITION;
}
}

View File

@@ -18,6 +18,8 @@ import java.util.Optional;
public class CustomMountPointChooser implements MountPointChooser {
public static final int POSITION = 0;
private static final Logger LOG = LoggerFactory.getLogger(CustomMountPointChooser.class);
private final Vault vault;
@@ -26,6 +28,11 @@ public class CustomMountPointChooser implements MountPointChooser {
this.vault = vault;
}
@Override
public boolean isApplicable() {
return true;
}
@Override
public Optional<Path> chooseMountPoint() {
//VaultSettings#getCustomMountPath already checks whether the saved custom mountpoint should be used
@@ -73,4 +80,9 @@ public class CustomMountPointChooser implements MountPointChooser {
LOG.debug("Successfully checked custom mount point: {}", mountPoint);
return false;
}
@Override
public int getPosition() {
return POSITION;
}
}

View File

@@ -1,65 +1,63 @@
package org.cryptomator.common.mountpoint;
import dagger.MapKey;
import org.cryptomator.common.vaults.Volume;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
/**
* Base interface for the Mountpoint-Choosing-Operation that results in the choice and
* preparation of a Mountpoint or an exception otherwise.<br>
* <p>All <i>MountPointChoosers (MPCs)</i> need to implement this class and must be added to
* the pool of possible MPCs by {@link MountPointChooserModule MountPointChooserModule.}
* The MountPointChooserModule requires all {@link dagger.Provides Providermethods} to
* be annotated with the {@link PhaseKey @PhaseKey-Annotation} and a <b>unique</b> Phase to
* allow the Module to sort them according to the phases' {@link Phase#getTiming()} timing.}
* The timing must be defined by the developer to reflect a useful execution order.
* the pool of possible MPCs by the {@link MountPointChooserModule MountPointChooserModule.}
* The MountPointChooserModule will sort them according to their {@link #getPosition() position.}
* The position must be defined by the developer to reflect a useful execution order;
* the order of execution of MPCs with equal position is undefined.
*
* <p><b>Phase-Uniqueness:</b> Phases must be unique, meaning that they must not be used
* to annotate more than <i>one</i> Providermethod. Define a new phase for each additional
* MPC that is added to the Module. Timings can be reused; the order of Phases with equal
* timing among themselves is undefined.
* <p>MPCs are executed by a {@link Volume} in ascedning order of their position to find
* and prepare a suitable Mountpoint for the Volume. The Volume has access to a
* {@link SortedSet} of MPCs in this specific order, that is provided by the Module.
* The Set only contains Choosers that were deemed {@link #isApplicable() applicable}
* by the Module.
*
* <p>MPCs are executed by a {@link Volume} in the order of their phase's timing to find
* and prepare a suitable Mountpoint for the Volume. The Volume only has access to a {@link Set}
* of MPCs in this specific order, that is provided by the Module; the according Phases and exact
* timings are inaccessible to the Volume. The Set only contains Choosers that were deemed
* {@link #isApplicable() applicable} by the Module.
* <p>At execution of a MPC {@link #chooseMountPoint()} is called to choose a Mountpoint
* according to the MPC's <i>strategy.</i> The <i>strategy</i> can involve reading configs,
* searching the filesystem, processing user-input or similar operations.
* If {@code #chooseMountPoint()} returns a non-null path (everthing but
* {@linkplain Optional#empty()}) the MPC's {@link #prepare(Path)}-Method is called and the
* MountPoint is verfied and/or prepared. In this case <i>no other MPC's will be called for
* this Volume, even if {@code #prepare(Path)} fails.</i>
*
* <p>At execution of a MPC {@link #chooseMountPoint()} and then {@link #prepare(Path)} are called
* by the Volume. If {@code #chooseMountPoint()} yields no result, the next MPC is executed
* without first calling the {@code #prepare(Path)}-Method of the current MPC.
* <p>If {@code #chooseMountPoint()} yields no result, the next MPC is executed
* <i>without</i> first calling the {@code #prepare(Path)}-Method of the current MPC.
* This is repeated until<br>
* <ul>
* <li><b>either</b> a Mountpoint is returned by {@code #chooseMountPoint()}
* and {@code #prepare(Path)} succeeds or fails</li>
* and {@code #prepare(Path)} succeeds or fails, ending the entire operation</li>
* <li><b>or</b> no MPC remains and an {@link InvalidMountPointException} is thrown.</li>
* </ul>
* If the {@code #prepare(Path)}-Method of a MPC fails the entire Mountpoint-Choosing-Operation
* If the {@code #prepare(Path)}-Method of a MPC fails, the entire Mountpoint-Choosing-Operation
* is aborted and the method should do all necessary cleanup before throwing the exception.
* If the preparation succeeds {@link #cleanup(Path)} can be used after unmount to do any
* remaining cleanup.
*/
public interface MountPointChooser {
public interface MountPointChooser extends Comparable<MountPointChooser> {
/**
* Called by the {@link MountPointChooserModule} to determine whether this MountPointChooser is
* applicable for the given Systemconfiguration.
*
* <p>The result of this method defaults to true. Developers should override this method to
* <p>Developers should override this method to
* check for Systemconfigurations that are unsuitable for this MPC.
*
* @return a boolean flag; true if applicable, else false.
* @see #chooseMountPoint()
*/
default boolean isApplicable() {
return true; //Usually most of the choosers should be applicable
}
boolean isApplicable();
/**
* Called by a {@link Volume} to do choose a Mountpoint according to the
* Called by a {@link Volume} to choose a Mountpoint according to the
* MountPointChoosers strategy.
*
* <p>This method is only called for MPCs that were deemed {@link #isApplicable() applicable}
@@ -128,43 +126,32 @@ public interface MountPointChooser {
}
/**
* The phases of the existing {@link MountPointChooser MountPointChoosers.}
* <p>The {@code Phases} of the MPCs are attached to them in the
* {@link MountPointChooserModule} by annotating them with the
* {@link PhaseKey @PhaseKey-Annotation.}
* <p>Each MPC must have a <b>unique</b> Phase that allows the Module to sort
* the MPCs according to their phases' {@link Phase#getTiming()} timing.}
* The timing must be defined by the developer to reflect a useful execution order.
* Called by the {@link MountPointChooserModule} to sort the available MPCs
* and determine their execution order.
* The position must be defined by the developer to reflect a useful execution order.
* MPCs with lower positions will be placed at lower indices in the resulting
* {@link SortedSet} and will be executed with higher probability.
* The order of execution of MPCs with equal position is undefined.
*
* <p><b>Phase-Uniqueness:</b> Phases must be unique, meaning that they must not be used
* to annotate more than <i>one</i> Providermethod. Define a new phase for each additional
* MPC that is added to the Module. Timings can be reused; the order of Phases with equal
* timings among themselves is undefined.
* @return the position of this MPC.
*/
enum Phase {
int getPosition();
CUSTOM_MOUNTPOINT(0),
CUSTOM_DRIVELETTER(1),
AVAILABLE_DRIVELETTER(2),
TEMPORARY_MOUNTPOINT(3);
private final int timing;
Phase(int timing) {
this.timing = timing;
}
public int getTiming() {
return timing;
}
}
@MapKey
@interface PhaseKey {
Phase value();
/**
* Called by the {@link MountPointChooserModule} to determine the execution order
* of the registered MPCs. <b>Implementations usually should not override this
* method.</b> This default implementation sorts the MPCs in ascending order
* of their {@link #getPosition() position.}<br>
* <br>
* <b>Original description:</b>
* <p>{@inheritDoc}
*
* @implNote This default implementation sorts the MPCs in ascending order
* of their {@link #getPosition() position.}
*/
@Override
default int compareTo(MountPointChooser other) {
//Sort by position (ascending order)
return Integer.compare(this.getPosition(), other.getPosition());
}
}

View File

@@ -3,16 +3,13 @@ package org.cryptomator.common.mountpoint;
import com.google.common.collect.ImmutableSet;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.IntoSet;
import org.cryptomator.common.Environment;
import org.cryptomator.common.mountpoint.MountPointChooser.Phase;
import org.cryptomator.common.vaults.PerVault;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.WindowsDriveLetters;
import javax.inject.Named;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
/**
@@ -25,32 +22,28 @@ import java.util.Set;
public abstract class MountPointChooserModule {
@Provides
@IntoMap
@MountPointChooser.PhaseKey(Phase.CUSTOM_MOUNTPOINT)
@IntoSet
@PerVault
public static MountPointChooser provideCustomMountPointChooser(Vault vault) {
return new CustomMountPointChooser(vault);
}
@Provides
@IntoMap
@MountPointChooser.PhaseKey(Phase.CUSTOM_DRIVELETTER)
@IntoSet
@PerVault
public static MountPointChooser provideCustomDriveLetterChooser(Vault vault) {
return new CustomDriveLetterChooser(vault);
}
@Provides
@IntoMap
@MountPointChooser.PhaseKey(Phase.AVAILABLE_DRIVELETTER)
@IntoSet
@PerVault
public static MountPointChooser provideAvailableDriveLetterChooser(WindowsDriveLetters windowsDriveLetters) {
return new AvailableDriveLetterChooser(windowsDriveLetters);
}
@Provides
@IntoMap
@MountPointChooser.PhaseKey(Phase.TEMPORARY_MOUNTPOINT)
@IntoSet
@PerVault
public static MountPointChooser provideTemporaryMountPointChooser(Vault vault, Environment environment) {
return new TemporaryMountPointChooser(vault, environment);
@@ -59,12 +52,8 @@ public abstract class MountPointChooserModule {
@Provides
@PerVault
@Named("orderedValidMountPointChoosers")
public static Set<MountPointChooser> provideOrderedValidMountPointChoosers(Map<Phase, MountPointChooser> chooserMap) {
public static Set<MountPointChooser> provideOrderedValidMountPointChoosers(Set<MountPointChooser> choosers) {
//Sorted Set
return chooserMap.entrySet().stream()
.sorted(Comparator.comparingInt(value -> value.getKey().getTiming()))
.map(Map.Entry::getValue)
.filter(MountPointChooser::isApplicable)
.collect(ImmutableSet.toImmutableSet());
return choosers.stream().sorted().filter(MountPointChooser::isApplicable).collect(ImmutableSet.toImmutableSet());
}
}

View File

@@ -15,6 +15,8 @@ import java.util.Optional;
public class TemporaryMountPointChooser implements MountPointChooser {
public static final int POSITION = 300;
private static final Logger LOG = LoggerFactory.getLogger(TemporaryMountPointChooser.class);
private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
@@ -85,4 +87,9 @@ public class TemporaryMountPointChooser implements MountPointChooser {
LOG.warn("Could not delete mount point: {}", e.getMessage());
}
}
@Override
public int getPosition() {
return POSITION;
}
}