mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 18:21:26 +00:00
Changed contracts in MPC interface
Added Volume parameter to the method signature of all MPC methods and updated implementations to use the change. Changed contract of the MPC interface: Validation of the MPC (call to #isApplicable()) moved from the Module to the Volume. Updated docs to reflect those changes. Fixed typos. Updated method/qualifier names. Updated implementation of #provideOrdered(Valid)MountPointChoosers() to reflect this change and to build the set differently. Updated #determineMountPoint() to work with the new set.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.cryptomator.common.mountpoint;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.common.vaults.WindowsDriveLetters;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -19,12 +20,12 @@ public class AvailableDriveLetterChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
public boolean isApplicable(Volume caller) {
|
||||
return SystemUtils.IS_OS_WINDOWS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> chooseMountPoint() {
|
||||
public Optional<Path> chooseMountPoint(Volume caller) {
|
||||
return this.windowsDriveLetters.getAvailableDriveLetterPath();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.cryptomator.common.mountpoint;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.nio.file.Path;
|
||||
@@ -20,12 +21,12 @@ public class CustomDriveLetterChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
public boolean isApplicable(Volume caller) {
|
||||
return SystemUtils.IS_OS_WINDOWS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> chooseMountPoint() {
|
||||
public Optional<Path> chooseMountPoint(Volume caller) {
|
||||
return this.vaultSettings.getWinDriveLetter().map(letter -> letter.charAt(0) + ":\\").map(Paths::get);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.cryptomator.common.mountpoint;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -30,18 +31,18 @@ public class CustomMountPointChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
public boolean isApplicable(Volume caller) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> chooseMountPoint() {
|
||||
public Optional<Path> chooseMountPoint(Volume caller) {
|
||||
//VaultSettings#getCustomMountPath already checks whether the saved custom mountpoint should be used
|
||||
return this.vault.getVaultSettings().getCustomMountPath().map(Paths::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(Path mountPoint) throws InvalidMountPointException {
|
||||
public boolean prepare(Volume caller, Path mountPoint) throws InvalidMountPointException {
|
||||
switch (this.vault.getMountPointRequirement()) {
|
||||
case PARENT_NO_MOUNT_POINT -> prepareParentNoMountPoint(mountPoint);
|
||||
case EMPTY_MOUNT_POINT -> prepareEmptyMountPoint(mountPoint);
|
||||
|
||||
@@ -16,70 +16,76 @@ import java.util.SortedSet;
|
||||
* The priority must be defined by the developer to reflect a useful execution order;
|
||||
* the order of execution of MPCs with equal priority is undefined.
|
||||
*
|
||||
* <p>MPCs are executed by a {@link Volume} in ascedning order of their priority 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 ascending order of their priority
|
||||
* (smaller priorities are tried first) 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 contains all available Choosers, even if they
|
||||
* are not {@link #isApplicable(Volume) applicable} for the Vault/Volume. The Volume must
|
||||
* check whether a MPC is applicable by invoking {@code #isApplicable(Volume)} on it
|
||||
* <i>before</i> calling {@code #chooseMountPoint(Volume)}.
|
||||
*
|
||||
* <p>At execution of a MPC {@link #chooseMountPoint()} is called to choose a mountpoint
|
||||
* <p>At execution of a MPC {@link #chooseMountPoint(Volume)} 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>
|
||||
* If {@code #chooseMountPoint(Volume)} returns a non-null path (everything but
|
||||
* {@linkplain Optional#empty()}) the MPC's {@link #prepare(Volume, Path)} method is called and the
|
||||
* MountPoint is verified and/or prepared. In this case <i>no other MPC's will be called for
|
||||
* this volume, even if {@code #prepare(Volume, Path)} fails.</i>
|
||||
*
|
||||
* <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.
|
||||
* <p>If {@code #chooseMountPoint(Volume)} yields no result, the next MPC is executed
|
||||
* <i>without</i> first calling the {@code #prepare(Volume, 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, ending the entire operation</li>
|
||||
* <li><b>either</b> a mountpoint is returned by {@code #chooseMountPoint(Volume)}
|
||||
* and {@code #prepare(Volume, 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
|
||||
* 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
|
||||
* If the {@code #prepare(Volume, 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(Volume, Path)} can be used after unmount to do any
|
||||
* remaining cleanup.
|
||||
*/
|
||||
public interface MountPointChooser extends Comparable<MountPointChooser> {
|
||||
|
||||
/**
|
||||
* Called by the {@link MountPointChooserModule} to determine whether this MountPointChooser is
|
||||
* applicable for the given Systemconfiguration.
|
||||
* Called by the {@link Volume} to determine whether this MountPointChooser is
|
||||
* applicable for mounting the Vault/Volume, especially with regard to the
|
||||
* current system configuration and particularities of the Volume type.
|
||||
*
|
||||
* <p>Developers should override this method to
|
||||
* check for Systemconfigurations that are unsuitable for this MPC.
|
||||
* <p>Developers should override this method to check for system configurations
|
||||
* that are unsuitable for this MPC.
|
||||
*
|
||||
* @param caller The Volume that is calling the method to determine applicability of the MPC
|
||||
* @return a boolean flag; true if applicable, else false.
|
||||
* @see #chooseMountPoint()
|
||||
* @see #chooseMountPoint(Volume)
|
||||
*/
|
||||
boolean isApplicable();
|
||||
boolean isApplicable(Volume caller);
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* by the {@link MountPointChooserModule MountPointChooserModule.}
|
||||
* <p>This method must only be called for MPCs that were deemed
|
||||
* {@link #isApplicable(Volume) applicable} by the {@link Volume Volume.}
|
||||
* Developers should override this method to find or extract a mountpoint for
|
||||
* the volume <b>without</b> preparing it. Preparation should be done by
|
||||
* {@link #prepare(Path)} instead.
|
||||
* {@link #prepare(Volume, Path)} instead.
|
||||
* Exceptions in this method should be handled gracefully and result in returning
|
||||
* {@link Optional#empty()} instead of throwing an exception.
|
||||
*
|
||||
* @param caller The Volume that is calling the method to choose a mountpoint
|
||||
* @return the chosen path or {@link Optional#empty()} if an exception occurred
|
||||
* or no mountpoint could be found.
|
||||
* @see #isApplicable()
|
||||
* @see #prepare(Path)
|
||||
* @see #isApplicable(Volume)
|
||||
* @see #prepare(Volume, Path)
|
||||
*/
|
||||
Optional<Path> chooseMountPoint();
|
||||
Optional<Path> chooseMountPoint(Volume caller);
|
||||
|
||||
/**
|
||||
* Called by a {@link Volume} to prepare and/or verify the chosen mountpoint.<br>
|
||||
* This method is only called if the {@link #chooseMountPoint()}-Method of the same
|
||||
* MountPointChooser returned a path.
|
||||
* This method is only called if the {@link #chooseMountPoint(Volume)} method
|
||||
* of the same MountPointChooser returned a path.
|
||||
*
|
||||
* <p>Developers should override this method to prepare the mountpoint for
|
||||
* the volume and check for any obstacles that could hinder the mount operation.
|
||||
@@ -92,37 +98,39 @@ public interface MountPointChooser extends Comparable<MountPointChooser> {
|
||||
*
|
||||
* <p>Often the preparation of a mountpoint involves creating files or others
|
||||
* actions that require cleaning up after the volume is unmounted.
|
||||
* In this case developers should override the {@link #cleanup(Path)}-Method
|
||||
* and return {@code true} to the volume to indicate that the
|
||||
* {@code #cleanup}-Method of this MPC should be called after unmount.
|
||||
* In this case developers should override the {@link #cleanup(Volume, Path)}
|
||||
* method and return {@code true} to the volume to indicate that the
|
||||
* {@code #cleanup} method of this MPC should be called after unmount.
|
||||
*
|
||||
* <p><b>Please note:</b> If this method fails the entire
|
||||
* Mountpoint-Choosing-Operation is aborted without calling {@link #cleanup(Path)}
|
||||
* or any other MPCs. Therefore this method should do all necessary cleanup
|
||||
* before throwing the exception.
|
||||
* Mountpoint-Choosing-Operation is aborted without calling
|
||||
* {@link #cleanup(Volume, Path)} or any other MPCs. Therefore this method should
|
||||
* do all necessary cleanup before throwing the exception.
|
||||
*
|
||||
* @param mountPoint the mountpoint chosen by {@link #chooseMountPoint()}
|
||||
* @param caller The Volume that is calling the method to prepare a mountpoint
|
||||
* @param mountPoint the mountpoint chosen by {@link #chooseMountPoint(Volume)}
|
||||
* @return a boolean flag; true if cleanup is needed, false otherwise
|
||||
* @throws InvalidMountPointException if the preparation fails
|
||||
* @see #chooseMountPoint()
|
||||
* @see #cleanup(Path)
|
||||
* @see #chooseMountPoint(Volume)
|
||||
* @see #cleanup(Volume, Path)
|
||||
*/
|
||||
default boolean prepare(Path mountPoint) throws InvalidMountPointException {
|
||||
default boolean prepare(Volume caller, Path mountPoint) throws InvalidMountPointException {
|
||||
return false; //NO-OP
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a {@link Volume} to do any cleanup needed after unmount.
|
||||
*
|
||||
* <p>This method is only called if the {@link #prepare(Path)}-Method of the same
|
||||
* MountPointChooser returned {@code true}. Typically developers want to
|
||||
* <p>This method is only called if the {@link #prepare(Volume, Path)} method
|
||||
* of the same MountPointChooser returned {@code true}. Typically developers want to
|
||||
* delete any files created prior to mount or do similar tasks.<br>
|
||||
* Exceptions in this method should be handled gracefully.
|
||||
*
|
||||
* @param mountPoint the mountpoint that was prepared by {@link #prepare(Path)}
|
||||
* @see #prepare(Path)
|
||||
* @param caller The Volume that is calling the method to cleanup the prepared mountpoint
|
||||
* @param mountPoint the mountpoint that was prepared by {@link #prepare(Volume, Path)}
|
||||
* @see #prepare(Volume, Path)
|
||||
*/
|
||||
default void cleanup(Path mountPoint) {
|
||||
default void cleanup(Volume caller, Path mountPoint) {
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
@@ -139,10 +147,9 @@ public interface MountPointChooser extends Comparable<MountPointChooser> {
|
||||
int getPriority();
|
||||
|
||||
/**
|
||||
* 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 #getPriority() priority.}<br>
|
||||
* Called by the {@link Volume} to determine the execution order of the registered MPCs.
|
||||
* <b>Implementations usually may not override this method.</b> This default implementation
|
||||
* sorts the MPCs in ascending order of their {@link #getPriority() priority.}<br>
|
||||
* <br>
|
||||
* <b>Original description:</b>
|
||||
* <p>{@inheritDoc}
|
||||
|
||||
@@ -8,7 +8,6 @@ import dagger.multibindings.IntoSet;
|
||||
import org.cryptomator.common.vaults.PerVault;
|
||||
|
||||
import javax.inject.Named;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
@@ -43,9 +42,9 @@ public abstract class MountPointChooserModule {
|
||||
|
||||
@Provides
|
||||
@PerVault
|
||||
@Named("orderedValidMountPointChoosers")
|
||||
public static SortedSet<MountPointChooser> provideOrderedValidMountPointChoosers(Set<MountPointChooser> choosers) {
|
||||
//The natural order is defined by MountPointChooser#compareTo
|
||||
return choosers.stream().filter(MountPointChooser::isApplicable).collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()));
|
||||
@Named("orderedMountPointChoosers")
|
||||
public static SortedSet<MountPointChooser> provideOrderedMountPointChoosers(Set<MountPointChooser> choosers) {
|
||||
//Sort by natural order. The natural order is defined by MountPointChooser#compareTo
|
||||
return ImmutableSortedSet.copyOf(choosers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.cryptomator.common.mountpoint;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -31,7 +32,7 @@ public class TemporaryMountPointChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
public boolean isApplicable(Volume caller) {
|
||||
if (this.environment.getMountPointsDir().isEmpty()) {
|
||||
LOG.warn("\"cryptomator.mountPointsDir\" is not set to a valid path!");
|
||||
return false;
|
||||
@@ -40,7 +41,7 @@ public class TemporaryMountPointChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> chooseMountPoint() {
|
||||
public Optional<Path> chooseMountPoint(Volume caller) {
|
||||
return this.environment.getMountPointsDir().map(this::choose);
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ public class TemporaryMountPointChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(Path mountPoint) throws InvalidMountPointException {
|
||||
public boolean prepare(Volume caller, Path mountPoint) throws InvalidMountPointException {
|
||||
// https://github.com/osxfuse/osxfuse/issues/306#issuecomment-245114592:
|
||||
// In order to allow non-admin users to mount FUSE volumes in `/Volumes`,
|
||||
// starting with version 3.5.0, FUSE will create non-existent mount points automatically.
|
||||
@@ -83,7 +84,7 @@ public class TemporaryMountPointChooser implements MountPointChooser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup(Path mountPoint) {
|
||||
public void cleanup(Volume caller, Path mountPoint) {
|
||||
try {
|
||||
Files.delete(mountPoint);
|
||||
LOG.debug("Successfully deleted mount point: {}", mountPoint);
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.cryptomator.common.mountpoint.MountPointChooser;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public abstract class AbstractVolume implements Volume {
|
||||
|
||||
@@ -24,25 +25,31 @@ public abstract class AbstractVolume implements Volume {
|
||||
}
|
||||
|
||||
protected Path determineMountPoint() throws InvalidMountPointException {
|
||||
SortedSet<MountPointChooser> checkedChoosers = new TreeSet<>(); //Natural order
|
||||
for (MountPointChooser chooser : this.choosers) {
|
||||
Optional<Path> chosenPath = chooser.chooseMountPoint();
|
||||
if(!chooser.isApplicable(this)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<Path> chosenPath = chooser.chooseMountPoint(this);
|
||||
checkedChoosers.add(chooser); //Consider a chooser checked if it's #chooseMountPoint() method was called
|
||||
if (chosenPath.isEmpty()) {
|
||||
//Chooser was applicable, but couldn't find a feasible mountpoint
|
||||
continue;
|
||||
}
|
||||
this.cleanupRequired = chooser.prepare(chosenPath.get()); //Fail entirely if an Exception occurs
|
||||
this.cleanupRequired = chooser.prepare(this, chosenPath.get()); //Fail entirely if an Exception occurs
|
||||
this.usedChooser = chooser;
|
||||
return chosenPath.get();
|
||||
}
|
||||
//SortedSet#stream() should return a sorted stream (that's what it's docs and the docs of #spliterator() say, even if they are not 100% clear for me.)
|
||||
//We want to keep that order, that's why we use ImmutableSet#toImmutableSet() to collect (even if it doesn't implement SortedSet, it's docs promise use encounter ordering.)
|
||||
String tried = Joiner.on(", ").join(this.choosers.stream().map((mpc) -> mpc.getClass().getTypeName()).collect(ImmutableSet.toImmutableSet()));
|
||||
throw new InvalidMountPointException(String.format("No feasible MountPoint found! Tried %s", tried));
|
||||
String checked = Joiner.on(", ").join(checkedChoosers.stream().map((mpc) -> mpc.getClass().getTypeName()).collect(ImmutableSet.toImmutableSet()));
|
||||
throw new InvalidMountPointException(String.format("No feasible MountPoint found! Checked %s", checked));
|
||||
}
|
||||
|
||||
protected void cleanupMountPoint() {
|
||||
if (this.cleanupRequired) {
|
||||
this.usedChooser.cleanup(this.mountPoint);
|
||||
this.usedChooser.cleanup(this, this.mountPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public class DokanyVolume extends AbstractVolume {
|
||||
private Mount mount;
|
||||
|
||||
@Inject
|
||||
public DokanyVolume(VaultSettings vaultSettings, ExecutorService executorService, @Named("orderedValidMountPointChoosers") SortedSet<MountPointChooser> choosers) {
|
||||
public DokanyVolume(VaultSettings vaultSettings, ExecutorService executorService, @Named("orderedMountPointChoosers") SortedSet<MountPointChooser> choosers) {
|
||||
super(choosers);
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.mountFactory = new MountFactory(executorService);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class FuseVolume extends AbstractVolume {
|
||||
private Mount mount;
|
||||
|
||||
@Inject
|
||||
public FuseVolume(@Named("orderedValidMountPointChoosers") SortedSet<MountPointChooser> choosers) {
|
||||
public FuseVolume(@Named("orderedMountPointChoosers") SortedSet<MountPointChooser> choosers) {
|
||||
super(choosers);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user