Show stack trace in case of unexpected exceptions

This commit is contained in:
Sebastian Stenzel
2019-11-27 15:44:53 +01:00
parent 94e3b21e44
commit 7d0bdc1a63
8 changed files with 160 additions and 2 deletions
@@ -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");
@@ -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;
}
}
@@ -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);
@@ -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());
}
}
@@ -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());
}
}
@@ -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>
@@ -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>
@@ -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