[FEATURE] Added exception handlers

This commit is contained in:
Jeroen Ketelaar
2019-05-21 23:07:54 -05:00
parent a32c3fa30b
commit 32ce5c0cda
3 changed files with 221 additions and 2 deletions
@@ -0,0 +1,88 @@
package org.parabot.environment.handlers.exceptions;
/**
* Class to be implemented that allows multiple types of exception handlers
*/
public abstract class ExceptionHandler implements Thread.UncaughtExceptionHandler {
/**
* The name of the exception handler
*/
private final String name;
/**
* The status of the exception handler; Defines if the exception handler is enabled or disabled
*/
private boolean enabled = true;
/**
* The type the handler is meant for
*/
private ExceptionType exceptionType;
public ExceptionHandler(String name, ExceptionType exceptionType) {
this.name = name;
this.exceptionType = exceptionType;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
this.handle(e);
}
/**
* Writes the exception to class extending this abstract class
*
* @param e
*/
public abstract void handle(Throwable e);
/**
* Returns if the exception handler is enabled or disabled
*
* @return
*/
public boolean isEnabled() {
return enabled;
}
/**
* Sets the enabled status of the exception handler
*
* @param enabled
*
* @return
*/
public ExceptionHandler setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}
public ExceptionType getExceptionType() {
return exceptionType;
}
public ExceptionHandler setExceptionType(ExceptionType exceptionType) {
this.exceptionType = exceptionType;
return this;
}
public String getName() {
return name;
}
public enum ExceptionType {
SERVER("Server"),
SCRIPT("Script"),
CLIENT("Client");
private String name;
ExceptionType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
@@ -0,0 +1,125 @@
package org.parabot.environment.handlers.exceptions;
import org.parabot.core.Directories;
import org.parabot.core.ui.utils.UILog;
import org.parabot.environment.api.utils.FileUtil;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
/**
* Writes exceptions to a file and reports the file location back to the user
*/
public class FileExceptionHandler extends ExceptionHandler {
/**
* Directory where the reports get written to
*/
private final File reportsDirectory;
/**
* Defines if the alert should popup during this client instance again
*/
private boolean ignored = false;
/**
* Initializes the exception handler and ensures the reports directory is created and writable
*/
public FileExceptionHandler(ExceptionType exceptionType) {
super("File exception handler", exceptionType);
this.reportsDirectory = new File(Directories.getWorkspace(), "reports");
if (!this.reportsDirectory.exists() || !this.reportsDirectory.isDirectory()) {
this.reportsDirectory.mkdir();
}
this.cleanOldErrors();
}
@Override
public void handle(Throwable e) {
File report = new File(this.reportsDirectory, "report-" + (System.currentTimeMillis() / 1000) + ".txt");
try {
report.createNewFile();
StringBuilder reportContent = new StringBuilder();
reportContent.append(e.getMessage() + "\n\n");
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
reportContent.append(stackTraceElement);
}
FileUtil.writeFileContents(report, reportContent.toString());
if (!ignored) {
displayAlert(report);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public boolean isIgnored() {
return ignored;
}
public FileExceptionHandler setIgnored(boolean ignored) {
this.ignored = ignored;
return this;
}
public File getReportsDirectory() {
return reportsDirectory;
}
/**
* Displays the dialog of the alert
*
* @param report
*/
private void displayAlert(File report) {
int response = UILog.alert(
"Error occurred",
"We are sorry to inform you that an error occurred within Parabot.\n\n" +
"The error has been written to a report file.\n" +
"Please report the error to the Parabot staff with as much information as possible.",
new Object[]{
"Close",
"Open report",
"Ignore " + this.getExceptionType().getName().toLowerCase() + " errors" },
1,
JOptionPane.WARNING_MESSAGE
);
switch (response) {
case 1:
try {
Desktop.getDesktop().open(report);
} catch (Exception ex) {
ex.printStackTrace();
}
break;
case 2:
ignored = true;
break;
}
}
/**
* Remove errors older than 24 hours
*/
private void cleanOldErrors() {
File[] reports = this.reportsDirectory.listFiles();
if (reports != null) {
for (File report : reports) {
if (report.isFile()) {
if ((System.currentTimeMillis() - report.lastModified()) / 1000 > 60 * 60 * 24) {
report.delete();
}
}
}
}
}
}
@@ -3,6 +3,8 @@ package org.parabot.environment.servers.executers;
import org.parabot.core.Context;
import org.parabot.core.ui.BotUI;
import org.parabot.core.ui.components.PaintComponent;
import org.parabot.environment.handlers.exceptions.ExceptionHandler;
import org.parabot.environment.handlers.exceptions.FileExceptionHandler;
import org.parabot.environment.servers.ServerProvider;
/**
@@ -15,7 +17,7 @@ public abstract class ServerExecuter {
public abstract void run();
public void finalize(final ServerProvider provider, final String serverName) {
new Thread(new Runnable() {
Thread serverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
@@ -30,7 +32,11 @@ public abstract class ServerExecuter {
t.printStackTrace();
}
}
}).start();
});
serverThread.setUncaughtExceptionHandler(new FileExceptionHandler(ExceptionHandler.ExceptionType.SERVER));
serverThread.start();
}
}