Преглед на файлове

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.
JaniruTEC преди 4 години
родител
ревизия
d295084312

+ 3 - 2
main/commons/src/main/java/org/cryptomator/common/mountpoint/AvailableDriveLetterChooser.java

@@ -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();
 	}
 

+ 3 - 2
main/commons/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java

@@ -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);
 	}
 

+ 4 - 3
main/commons/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java

@@ -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);

+ 57 - 50
main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointChooser.java

@@ -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}

+ 4 - 5
main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointChooserModule.java

@@ -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);
 	}
 }

+ 5 - 4
main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java

@@ -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);

+ 12 - 5
main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java

@@ -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);
 		}
 	}
 

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java

@@ -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);

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/vaults/FuseVolume.java

@@ -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);
 	}