فهرست منبع

Show stack trace in case of unexpected exceptions

Sebastian Stenzel 5 سال پیش
والد
کامیت
7d0bdc1a63

+ 1 - 0
main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java

@@ -21,6 +21,7 @@ public enum FxmlFile {
 	RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
 	REMOVE_VAULT("/fxml/remove_vault.fxml"), //
 	UNLOCK("/fxml/unlock.fxml"),
+	UNLOCK_GENERIC_ERROR("/fxml/unlock_generic_error.fxml"), //
 	UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), //
 	VAULT_OPTIONS("/fxml/vault_options.fxml"), //
 	WRONGFILEALERT("/fxml/wrongfilealert.fxml");

+ 28 - 0
main/ui/src/main/java/org/cryptomator/ui/common/StackTraceController.java

@@ -0,0 +1,28 @@
+package org.cryptomator.ui.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
+public class StackTraceController implements FxController {
+
+	private final String stackTrace;
+
+	public StackTraceController(Exception cause) {
+		this.stackTrace = provideStackTrace(cause);
+	}
+
+	static String provideStackTrace(Exception cause) {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		cause.printStackTrace(new PrintStream(baos));
+		return baos.toString(StandardCharsets.UTF_8);
+	}
+
+	/* Getter/Setter */
+
+	public String getStackTrace() {
+		return stackTrace;
+	}
+
+
+}

+ 9 - 2
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java

@@ -7,6 +7,7 @@ import javafx.animation.Timeline;
 import javafx.beans.binding.Bindings;
 import javafx.beans.binding.ObjectBinding;
 import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.value.WritableValue;
@@ -32,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import java.nio.file.DirectoryNotEmptyException;
 import java.nio.file.NotDirectoryException;
 import java.util.Arrays;
@@ -49,19 +51,23 @@ public class UnlockController implements FxController {
 	private final ObjectBinding<ContentDisplay> unlockButtonState;
 	private final Optional<KeychainAccess> keychainAccess;
 	private final Lazy<Scene> successScene;
+	private final Lazy<Scene> genericErrorScene;
+	private final ObjectProperty<Exception> genericErrorCause;
 	private final ForgetPasswordComponent.Builder forgetPassword;
 	private final BooleanProperty unlockButtonDisabled;
 	public NiceSecurePasswordField passwordField;
 	public CheckBox savePassword;
 
 	@Inject
-	public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, ForgetPasswordComponent.Builder forgetPassword) {
+	public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_GENERIC_ERROR) Lazy<Scene> genericErrorScene, @Named("genericErrorCause") ObjectProperty<Exception> genericErrorCause, ForgetPasswordComponent.Builder forgetPassword) {
 		this.window = window;
 		this.vault = vault;
 		this.executor = executor;
 		this.unlockButtonState = Bindings.createObjectBinding(this::getUnlockButtonState, vault.stateProperty());
 		this.keychainAccess = keychainAccess;
 		this.successScene = successScene;
+		this.genericErrorScene = genericErrorScene;
+		this.genericErrorCause = genericErrorCause;
 		this.forgetPassword = forgetPassword;
 		this.unlockButtonDisabled = new SimpleBooleanProperty();
 	}
@@ -110,7 +116,8 @@ public class UnlockController implements FxController {
 			// TODO
 		}).onError(Exception.class, e -> { // including RuntimeExceptions
 			LOG.error("Unlock failed for technical reasons.", e);
-			// TODO
+			genericErrorCause.set(e);
+			window.setScene(genericErrorScene.get());
 		}).andFinally(() -> {
 			if (!vault.isUnlocked()) {
 				vault.setState(VaultState.LOCKED);

+ 29 - 0
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockGenericErrorController.java

@@ -0,0 +1,29 @@
+package org.cryptomator.ui.unlock;
+
+import dagger.Lazy;
+import javafx.fxml.FXML;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+
+import javax.inject.Inject;
+
+@UnlockScoped
+public class UnlockGenericErrorController implements FxController {
+
+	private final Stage window;
+	private final Lazy<Scene> unlockScene;
+
+	@Inject
+	UnlockGenericErrorController(@UnlockWindow Stage window, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene) {
+		this.window = window;
+		this.unlockScene = unlockScene;
+	}
+
+	@FXML
+	public void back() {
+		window.setScene(unlockScene.get());
+	}
+}

+ 29 - 0
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java

@@ -4,6 +4,8 @@ import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.IntoMap;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
 import javafx.scene.Scene;
 import javafx.scene.image.Image;
 import javafx.stage.Modality;
@@ -14,6 +16,7 @@ import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.FxControllerKey;
 import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
+import org.cryptomator.ui.common.StackTraceController;
 import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
 
 import javax.inject.Named;
@@ -44,6 +47,13 @@ abstract class UnlockModule {
 		return stage;
 	}
 
+	@Provides
+	@Named("genericErrorCause")
+	@UnlockScoped
+	static ObjectProperty<Exception> provideGenericErrorCause() {
+		return new SimpleObjectProperty<>();
+	}
+
 	@Provides
 	@FxmlScene(FxmlFile.UNLOCK)
 	@UnlockScoped
@@ -58,6 +68,13 @@ abstract class UnlockModule {
 		return fxmlLoaders.createScene("/fxml/unlock_success.fxml");
 	}
 
+	@Provides
+	@FxmlScene(FxmlFile.UNLOCK_GENERIC_ERROR)
+	@UnlockScoped
+	static Scene provideGenericErrorScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) {
+		return fxmlLoaders.createScene("/fxml/unlock_generic_error.fxml");
+	}
+
 
 	// ------------------
 
@@ -71,5 +88,17 @@ abstract class UnlockModule {
 	@FxControllerKey(UnlockSuccessController.class)
 	abstract FxController bindUnlockSuccessController(UnlockSuccessController controller);
 
+	@Binds
+	@IntoMap
+	@FxControllerKey(UnlockGenericErrorController.class)
+	abstract FxController bindUnlockGenericErrorController(UnlockGenericErrorController controller);
+
+	@Provides
+	@IntoMap
+	@FxControllerKey(StackTraceController.class)
+	static FxController provideStackTraceController(@Named("genericErrorCause") ObjectProperty<Exception> errorCause) {
+		return new StackTraceController(errorCause.get());
+	}
+
 
 }

+ 29 - 0
main/ui/src/main/resources/fxml/stacktrace.fxml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.TextArea?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.shape.Circle?>
+<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
+<VBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.common.StackTraceController"
+	  minWidth="300"
+	  spacing="12">
+	<children>
+		<HBox spacing="12" VBox.vgrow="ALWAYS">
+			<StackPane alignment="CENTER" HBox.hgrow="NEVER">
+				<Circle styleClass="glyph-icon-primary" radius="24"/>
+				<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
+			</StackPane>
+			<VBox spacing="6" HBox.hgrow="ALWAYS">
+				<Label text="%generic.error.title" wrapText="true"/>
+				<Label text="%generic.error.instruction" wrapText="true"/>
+			</VBox>
+		</HBox>
+
+		<TextArea text="${controller.stackTrace}" prefRowCount="5" editable="false"/>
+	</children>
+</VBox>

+ 32 - 0
main/ui/src/main/resources/fxml/unlock_generic_error.fxml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ButtonBar?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.layout.Region?>
+<VBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.unlock.UnlockGenericErrorController"
+	  minWidth="400"
+	  maxWidth="400"
+	  minHeight="145"
+	  spacing="12">
+	<padding>
+		<Insets topRightBottomLeft="12"/>
+	</padding>
+	<children>
+		<fx:include source="/fxml/stacktrace.fxml"/>
+
+		<Region VBox.vgrow="ALWAYS"/>
+
+		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
+			<ButtonBar buttonMinWidth="120" buttonOrder="B+U">
+				<buttons>
+					<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back"/>
+					<Region ButtonBar.buttonData="OTHER"/>
+				</buttons>
+			</ButtonBar>
+		</VBox>
+	</children>
+</VBox>

+ 3 - 0
main/ui/src/main/resources/i18n/strings.properties

@@ -11,6 +11,9 @@ generic.button.copy=Copy
 generic.button.done=Done
 generic.button.next=Next
 generic.button.print=Print
+## Error
+generic.error.title=An unexpected error occured
+generic.error.instruction=This should not have happened. Please report the error text below and include a description of what steps did lead to this error.
 
 # Tray Menu
 traymenu.showMainWindow=Show