Ignore the NPE which happens when dropping a rocket component as the

last component in the previous child element.  I can't seem to find a
better solution than to just eat the npe.
This commit is contained in:
kruland2607 2013-12-05 13:02:33 -06:00
parent c2d8314282
commit cbb9a48435

@ -13,49 +13,49 @@ import org.slf4j.LoggerFactory;
public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, ExceptionHandler { public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, ExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(SwingExceptionHandler.class); private static final Logger log = LoggerFactory.getLogger(SwingExceptionHandler.class);
private static final int MEMORY_RESERVE = 512 * 1024; private static final int MEMORY_RESERVE = 512 * 1024;
/** /**
* A memory reserve of 0.5 MB of memory, that can be freed when showing the dialog. * A memory reserve of 0.5 MB of memory, that can be freed when showing the dialog.
* <p> * <p>
* This field is package-private so that the JRE cannot optimize its use away. * This field is package-private so that the JRE cannot optimize its use away.
*/ */
volatile byte[] memoryReserve = null; volatile byte[] memoryReserve = null;
private volatile boolean handling = false; private volatile boolean handling = false;
@Override @Override
public void uncaughtException(final Thread thread, final Throwable throwable) { public void uncaughtException(final Thread thread, final Throwable throwable) {
// Free memory reserve if out of memory // Free memory reserve if out of memory
if (isOutOfMemoryError(throwable)) { if (isOutOfMemoryError(throwable)) {
memoryReserve = null; memoryReserve = null;
handling = false; handling = false;
log.error("Out of memory error detected", throwable); log.error("Out of memory error detected", throwable);
} }
if (isNonFatalJREBug(throwable)) { if (isNonFatalJREBug(throwable)) {
log.warn("Ignoring non-fatal JRE bug", throwable); log.warn("Ignoring non-fatal JRE bug", throwable);
return; return;
} }
log.error("Handling uncaught exception on thread=" + thread, throwable); log.error("Handling uncaught exception on thread=" + thread, throwable);
throwable.printStackTrace(); throwable.printStackTrace();
if (handling) { if (handling) {
log.warn("Exception is currently being handled, ignoring"); log.warn("Exception is currently being handled, ignoring");
return; return;
} }
try { try {
handling = true; handling = true;
// Show on the EDT // Show on the EDT
if (SwingUtilities.isEventDispatchThread()) { if (SwingUtilities.isEventDispatchThread()) {
log.info("Exception handler running on EDT, showing dialog"); log.info("Exception handler running on EDT, showing dialog");
@ -69,9 +69,9 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
} }
}); });
} }
} catch (Throwable ex) { } catch (Throwable ex) {
// Make sure the handler does not throw any exceptions // Make sure the handler does not throw any exceptions
try { try {
log.error("Caught exception while handling exception", ex); log.error("Caught exception while handling exception", ex);
@ -79,15 +79,15 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
ex.printStackTrace(); ex.printStackTrace();
} catch (Exception ignore) { } catch (Exception ignore) {
} }
} finally { } finally {
// Mark handling as completed // Mark handling as completed
handling = false; handling = false;
} }
} }
/** /**
* Handle an error condition programmatically without throwing an exception. * Handle an error condition programmatically without throwing an exception.
* This can be used in cases where recovery of the error is desirable. * This can be used in cases where recovery of the error is desirable.
@ -102,8 +102,8 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
log.error(message, new Throwable()); log.error(message, new Throwable());
handleErrorCondition(new InternalException(message)); handleErrorCondition(new InternalException(message));
} }
/** /**
* Handle an error condition programmatically without throwing an exception. * Handle an error condition programmatically without throwing an exception.
* This can be used in cases where recovery of the error is desirable. * This can be used in cases where recovery of the error is desirable.
@ -119,8 +119,8 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
log.error(message, exception); log.error(message, exception);
handleErrorCondition(new InternalException(message, exception)); handleErrorCondition(new InternalException(message, exception));
} }
/** /**
* Handle an error condition programmatically without throwing an exception. * Handle an error condition programmatically without throwing an exception.
* This can be used in cases where recovery of the error is desirable. * This can be used in cases where recovery of the error is desirable.
@ -137,7 +137,7 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
log.error("Error occurred", exception); log.error("Error occurred", exception);
} }
final Thread thread = Thread.currentThread(); final Thread thread = Thread.currentThread();
if (SwingUtilities.isEventDispatchThread()) { if (SwingUtilities.isEventDispatchThread()) {
log.info("Running in EDT, showing dialog"); log.info("Running in EDT, showing dialog");
this.showDialog(thread, exception); this.showDialog(thread, exception);
@ -155,8 +155,8 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
log.error("Exception occurred in error handler", e); log.error("Exception occurred in error handler", e);
} }
} }
/** /**
* The actual handling routine. * The actual handling routine.
* *
@ -164,82 +164,82 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
* @param e the exception. * @param e the exception.
*/ */
private void showDialog(Thread t, Throwable e) { private void showDialog(Thread t, Throwable e) {
// Out of memory // Out of memory
if (isOutOfMemoryError(e)) { if (isOutOfMemoryError(e)) {
log.info("Showing out-of-memory dialog"); log.info("Showing out-of-memory dialog");
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
new Object[] { new Object[] {
"OpenRocket is out of available memory!", "OpenRocket is out of available memory!",
"You should immediately close unnecessary design windows,", "You should immediately close unnecessary design windows,",
"save any unsaved designs and restart OpenRocket!" "save any unsaved designs and restart OpenRocket!"
}, "Out of memory", JOptionPane.ERROR_MESSAGE); }, "Out of memory", JOptionPane.ERROR_MESSAGE);
return; return;
} }
// Create the message // Create the message
String msg = e.getClass().getSimpleName() + ": " + e.getMessage(); String msg = e.getClass().getSimpleName() + ": " + e.getMessage();
if (msg.length() > 90) { if (msg.length() > 90) {
msg = msg.substring(0, 80) + "..."; msg = msg.substring(0, 80) + "...";
} }
// Unknown Error // Unknown Error
if (!(e instanceof Exception) && !(e instanceof LinkageError)) { if (!(e instanceof Exception) && !(e instanceof LinkageError)) {
log.info("Showing Error dialog"); log.info("Showing Error dialog");
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
new Object[] { new Object[] {
"An unknown Java error occurred:", "An unknown Java error occurred:",
msg, msg,
"<html>You should immediately close unnecessary design windows,<br>" + "<html>You should immediately close unnecessary design windows,<br>" +
"save any unsaved designs and restart OpenRocket!" "save any unsaved designs and restart OpenRocket!"
}, "Unknown Java error", JOptionPane.ERROR_MESSAGE); }, "Unknown Java error", JOptionPane.ERROR_MESSAGE);
return; return;
} }
// Normal exception, show question dialog // Normal exception, show question dialog
log.info("Showing Exception dialog"); log.info("Showing Exception dialog");
int selection = JOptionPane.showOptionDialog(null, new Object[] { int selection = JOptionPane.showOptionDialog(null, new Object[] {
"OpenRocket encountered an uncaught exception. This typically signifies " + "OpenRocket encountered an uncaught exception. This typically signifies " +
"a bug in the software.", "a bug in the software.",
"<html><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + msg + "</em>", "<html><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + msg + "</em>",
" ", " ",
"Please take a moment to report this bug to the developers.", "Please take a moment to report this bug to the developers.",
"This can be done automatically if you have an Internet connection." "This can be done automatically if you have an Internet connection."
}, "Uncaught exception", JOptionPane.DEFAULT_OPTION, }, "Uncaught exception", JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE, null, JOptionPane.ERROR_MESSAGE, null,
new Object[] { "View bug report", "Close" }, "View bug report"); new Object[] { "View bug report", "Close" }, "View bug report");
if (selection != 0) { if (selection != 0) {
// User cancelled // User cancelled
log.info(Markers.USER_MARKER, "User chose not to fill bug report"); log.info(Markers.USER_MARKER, "User chose not to fill bug report");
return; return;
} }
// Show bug report dialog // Show bug report dialog
log.info(Markers.USER_MARKER, "User requested sending bug report"); log.info(Markers.USER_MARKER, "User requested sending bug report");
BugReportDialog.showExceptionDialog(null, t, e); BugReportDialog.showExceptionDialog(null, t, e);
} }
/** /**
* Registers the uncaught exception handler. This should be used to ensure that * Registers the uncaught exception handler. This should be used to ensure that
* all necessary registrations are performed. * all necessary registrations are performed.
*/ */
public void registerExceptionHandler() { public void registerExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(this); Thread.setDefaultUncaughtExceptionHandler(this);
// Handler for modal dialogs of Sun's Java implementation // Handler for modal dialogs of Sun's Java implementation
// See bug ID 4499199. // See bug ID 4499199.
System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName()); System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());
reserveMemory(); reserveMemory();
} }
/** /**
* Reserve the buffer memory that is freed in case an OutOfMemoryError occurs. * Reserve the buffer memory that is freed in case an OutOfMemoryError occurs.
*/ */
@ -249,9 +249,9 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
memoryReserve[i] = (byte) i; memoryReserve[i] = (byte) i;
} }
} }
/** /**
* Return whether this throwable was caused by an OutOfMemoryError * Return whether this throwable was caused by an OutOfMemoryError
* condition. An exception is deemed to be caused by OutOfMemoryError * condition. An exception is deemed to be caused by OutOfMemoryError
@ -271,9 +271,9 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
} }
return false; return false;
} }
/** /**
* Handler used in modal dialogs by Sun Java implementation. * Handler used in modal dialogs by Sun Java implementation.
*/ */
@ -282,8 +282,8 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
Application.getExceptionHandler().uncaughtException(Thread.currentThread(), t); Application.getExceptionHandler().uncaughtException(Thread.currentThread(), t);
} }
} }
/** /**
* Detect various non-fatal Sun JRE bugs. * Detect various non-fatal Sun JRE bugs.
* *
@ -291,32 +291,32 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
* @return whether this exception should be ignored * @return whether this exception should be ignored
*/ */
private boolean isNonFatalJREBug(Throwable t) { private boolean isNonFatalJREBug(Throwable t) {
// NOTE: Calling method logs the entire throwable, so log only message here // NOTE: Calling method logs the entire throwable, so log only message here
/* /*
* Detect and ignore bug 6826104 in Sun JRE. * Detect and ignore bug 6826104 in Sun JRE.
*/ */
if (t instanceof NullPointerException) { if (t instanceof NullPointerException) {
StackTraceElement[] trace = t.getStackTrace(); StackTraceElement[] trace = t.getStackTrace();
if (trace.length > 3 && if (trace.length > 3 &&
trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") && trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") &&
trace[0].getMethodName().equals("restoreTransientFor") && trace[0].getMethodName().equals("restoreTransientFor") &&
trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") && trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") &&
trace[1].getMethodName().equals("removeFromTransientFors") && trace[1].getMethodName().equals("removeFromTransientFors") &&
trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") && trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") &&
trace[2].getMethodName().equals("setModalBlocked")) { trace[2].getMethodName().equals("setModalBlocked")) {
log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t); log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t);
return true; return true;
} }
} }
/* /*
* Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16. * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
*/ */
@ -326,26 +326,26 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
if (elements.length >= 3 && if (elements.length >= 3 &&
(buggyClass.equals(elements[0].getClassName()) || (buggyClass.equals(elements[0].getClassName()) ||
buggyClass.equals(elements[1].getClassName()) || buggyClass.equals(elements[1].getClassName()) ||
buggyClass.equals(elements[2].getClassName()))) { buggyClass.equals(elements[2].getClassName()))) {
log.warn("Ignoring Sun JRE bug 6828938: " + log.warn("Ignoring Sun JRE bug 6828938: " +
"(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6828938): " + t); "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6828938): " + t);
return true; return true;
} }
} }
/* /*
* Detect and ignore bug 6561072 in Sun JRE 1.6.0_? * Detect and ignore bug 6561072 in Sun JRE 1.6.0_?
*/ */
if (t instanceof NullPointerException) { if (t instanceof NullPointerException) {
StackTraceElement[] trace = t.getStackTrace(); StackTraceElement[] trace = t.getStackTrace();
if (trace.length > 3 && if (trace.length > 3 &&
trace[0].getClassName().equals("javax.swing.JComponent") && trace[0].getClassName().equals("javax.swing.JComponent") &&
trace[0].getMethodName().equals("repaint") && trace[0].getMethodName().equals("repaint") &&
trace[1].getClassName().equals("sun.swing.FilePane$2") && trace[1].getClassName().equals("sun.swing.FilePane$2") &&
trace[1].getMethodName().equals("repaintListSelection") && trace[1].getMethodName().equals("repaintListSelection") &&
trace[2].getClassName().equals("sun.swing.FilePane$2") && trace[2].getClassName().equals("sun.swing.FilePane$2") &&
trace[2].getMethodName().equals("repaintSelection")) { trace[2].getMethodName().equals("repaintSelection")) {
log.warn("Ignoring Sun JRE bug 6561072 " + log.warn("Ignoring Sun JRE bug 6561072 " +
@ -353,14 +353,14 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
return true; return true;
} }
} }
/* /*
* Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others * Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others
*/ */
if (t instanceof IllegalStateException) { if (t instanceof IllegalStateException) {
StackTraceElement[] trace = t.getStackTrace(); StackTraceElement[] trace = t.getStackTrace();
if (trace.length > 1 && if (trace.length > 1 &&
trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") && trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") &&
trace[0].getMethodName().equals("getBackBuffer")) { trace[0].getMethodName().equals("getBackBuffer")) {
@ -369,20 +369,20 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
return true; return true;
} }
} }
/* /*
* Detect and ignore bug in Sun JRE 1.6.0_19 * Detect and ignore bug in Sun JRE 1.6.0_19
*/ */
if (t instanceof NullPointerException) { if (t instanceof NullPointerException) {
StackTraceElement[] trace = t.getStackTrace(); StackTraceElement[] trace = t.getStackTrace();
if (trace.length > 3 && if (trace.length > 3 &&
trace[0].getClassName().equals("sun.awt.shell.Win32ShellFolder2") && trace[0].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
trace[0].getMethodName().equals("pidlsEqual") && trace[0].getMethodName().equals("pidlsEqual") &&
trace[1].getClassName().equals("sun.awt.shell.Win32ShellFolder2") && trace[1].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
trace[1].getMethodName().equals("equals") && trace[1].getMethodName().equals("equals") &&
trace[2].getClassName().equals("sun.awt.shell.Win32ShellFolderManager2") && trace[2].getClassName().equals("sun.awt.shell.Win32ShellFolderManager2") &&
trace[2].getMethodName().equals("isFileSystemRoot")) { trace[2].getMethodName().equals("isFileSystemRoot")) {
log.warn("Ignoring Sun JRE bug " + log.warn("Ignoring Sun JRE bug " +
@ -390,7 +390,7 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
return true; return true;
} }
} }
/* /*
* Detect Sun JRE bug in D3D * Detect Sun JRE bug in D3D
*/ */
@ -401,25 +401,43 @@ public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, E
return true; return true;
} }
} }
/*
* Detect and ignore DnD bug in component tree - related to 6560955 in Sun JRE.
*/
if (t instanceof NullPointerException) {
StackTraceElement[] trace = t.getStackTrace();
if (trace.length > 2 &&
trace[0].getClassName().equals("javax.swing.tree.TreePath") &&
trace[0].getMethodName().equals("pathByAddingChild") &&
trace[1].getClassName().equals("javax.swing.plaf.basic.BasicTreeUI") &&
trace[1].getMethodName().equals("getDropLineRect")) {
log.warn("Ignoring Sun JRE bug updating drop location " +
"(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6560955): " + t);
return true;
}
}
return false; return false;
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static class InternalException extends Exception { private static class InternalException extends Exception {
public InternalException() { public InternalException() {
super(); super();
} }
public InternalException(String message, Throwable cause) { public InternalException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public InternalException(String message) { public InternalException(String message) {
super(message); super(message);
} }
public InternalException(Throwable cause) { public InternalException(Throwable cause) {
super(cause); super(cause);
} }