Browse Source

stronger encapsulation of vault state await/signal mechanism

Sebastian Stenzel 4 years ago
parent
commit
24baa44e70

+ 3 - 20
main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java

@@ -44,9 +44,6 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
 
 import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
 
@@ -74,8 +71,6 @@ public class Vault {
 	private final StringBinding accessPoint;
 	private final BooleanBinding accessPointPresent;
 	private final BooleanProperty showingStats;
-	private final Lock lock = new ReentrantLock(); //FIXME: naming
-	private final Condition isLocked = lock.newCondition(); //FIXME: improve naming
 
 	private volatile Volume volume;
 
@@ -152,13 +147,6 @@ public class Vault {
 					if (throwable != null) {
 						LOG.warn("Unexpected unmount and lock of vault " + getDisplayName(), throwable);
 					}
-					lock.lock();
-					try {
-						isLocked.signal();
-					} finally {
-						lock.unlock();
-					}
-
 				});
 			} catch (Exception e) {
 				destroyCryptoFileSystem();
@@ -176,20 +164,15 @@ public class Vault {
 			volume.unmount();
 		}
 		destroyCryptoFileSystem();
-		lock.lock();
 		try {
-			while (state.get() != VaultState.Value.LOCKED) {
-				if (!isLocked.await(3000, TimeUnit.MILLISECONDS)) {
-					throw new VolumeException("Locking failed"); //FIXME: other exception
-				}
+			boolean locked = state.awaitState(VaultState.Value.LOCKED, 3000, TimeUnit.MILLISECONDS);
+			if (!locked) {
+				throw new VolumeException("Locking failed"); //FIXME: other exception
 			}
 		} catch (InterruptedException e) {
 			Thread.currentThread().interrupt();
 			throw new VolumeException("Lock failed."); //FIXME: other/new exception
-		} finally {
-			lock.unlock();
 		}
-
 	}
 
 	public void reveal(Volume.Revealer vaultRevealer) throws VolumeException {

+ 42 - 0
main/commons/src/main/java/org/cryptomator/common/vaults/VaultState.java

@@ -8,7 +8,11 @@ import javax.inject.Inject;
 import javafx.application.Platform;
 import javafx.beans.value.ObservableObjectValue;
 import javafx.beans.value.ObservableValueBase;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 @PerVault
 public class VaultState extends ObservableValueBase<VaultState.Value> implements ObservableObjectValue<VaultState.Value> {
@@ -48,6 +52,8 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
 	}
 
 	private final AtomicReference<Value> value;
+	private final Lock lock = new ReentrantLock();
+	private final Condition valueChanged = lock.newCondition();
 
 	@Inject
 	public VaultState(VaultState.Value initialValue) {
@@ -89,7 +95,43 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
 		}
 	}
 
+	/**
+	 * Waits for the specified time, until the desired state is reached.
+	 *
+	 * @param desiredState what state to wait for
+	 * @param time the maximum time to wait
+	 * @param unit the time unit of the {@code time} argument
+	 * @return {@code false} if the waiting time detectably elapsed before reaching {@code desiredState}
+	 * @throws InterruptedException if the current thread is interrupted
+	 */
+	public boolean awaitState(Value desiredState, long time, TimeUnit unit) throws InterruptedException {
+		lock.lock();
+		try {
+			long remaining = unit.convert(time, TimeUnit.NANOSECONDS);
+			while (value.get() != desiredState) {
+				if (remaining <= 0L) {
+					return false;
+				}
+				remaining = valueChanged.awaitNanos(remaining);
+			}
+			return true;
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	private void signal() {
+		lock.lock();
+		try {
+			valueChanged.signalAll();
+		} finally {
+			lock.unlock();
+		}
+	}
+
+	@Override
 	protected void fireValueChangedEvent() {
+		signal();
 		if (Platform.isFxApplicationThread()) {
 			super.fireValueChangedEvent();
 		} else {