X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fnet%2Fsf%2Fopenrocket%2Fgui%2Fmain%2FExceptionHandler.java;h=83301da729d0645a2e3c26c398eb835002c55551;hb=b1c573776a50dbf618f27898cdad90cafe9addc2;hp=702c3025cf5d866644f5a85dbf93d9e395f57bff;hpb=def27b03bd9ebe6628421ec61112ebe4f45f043d;p=debian%2Fopenrocket diff --git a/src/net/sf/openrocket/gui/main/ExceptionHandler.java b/src/net/sf/openrocket/gui/main/ExceptionHandler.java index 702c3025..83301da7 100644 --- a/src/net/sf/openrocket/gui/main/ExceptionHandler.java +++ b/src/net/sf/openrocket/gui/main/ExceptionHandler.java @@ -4,11 +4,16 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import net.sf.openrocket.gui.dialogs.BugReportDialog; +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.logging.TraceException; +import net.sf.openrocket.startup.Application; public class ExceptionHandler implements Thread.UncaughtExceptionHandler { - - private static final int MEMORY_RESERVE = 512*1024; + + private static final LogHelper log = Application.getLogger(); + + 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. @@ -19,51 +24,61 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { private static ExceptionHandler instance = null; - + private volatile boolean handling = false; - - + + @Override - public void uncaughtException(final Thread t, final Throwable e) { + public void uncaughtException(final Thread thread, final Throwable throwable) { // Free memory reserve if out of memory - if (isOutOfMemoryError(e)) { + if (isOutOfMemoryError(throwable)) { memoryReserve = null; handling = false; + log.error("Out of memory error detected", throwable); + } + + if (isNonFatalJREBug(throwable)) { + log.warn("Ignoring non-fatal JRE bug", throwable); + return; + } + + log.error("Handling uncaught exception on thread=" + thread, throwable); + throwable.printStackTrace(); + + if (handling) { + log.warn("Exception is currently being handled, ignoring"); + return; } - - e.printStackTrace(); try { - - if (handling) { - System.err.println("Exception is currently being handled, ignoring:"); - e.printStackTrace(); - return; - } - handling = true; // Show on the EDT if (SwingUtilities.isEventDispatchThread()) { - showDialog(t, e); + log.info("Exception handler running on EDT, showing dialog"); + showDialog(thread, throwable); } else { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - showDialog(t, e); - } - }); + log.info("Exception handler not on EDT, invoking dialog on EDT"); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + showDialog(thread, throwable); + } + }); } } catch (Throwable ex) { // Make sure the handler does not throw any exceptions try { + log.error("Caught exception while handling exception", ex); System.err.println("Exception in exception handler, dumping exception:"); ex.printStackTrace(); - } catch (Throwable ignore) { } + } catch (Exception ignore) { + } } finally { // Mark handling as completed @@ -71,27 +86,35 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { } } - + /** * Handle an error condition programmatically without throwing an exception. * This can be used in cases where recovery of the error is desirable. + *

+ * This method is guaranteed never to throw an exception, and can thus be safely + * used in finally blocks. * * @param message the error message. */ public static void handleErrorCondition(String message) { + log.error(1, message, new TraceException()); handleErrorCondition(new InternalException(message)); } - + /** * Handle an error condition programmatically without throwing an exception. * This can be used in cases where recovery of the error is desirable. + *

+ * This method is guaranteed never to throw an exception, and can thus be safely + * used in finally blocks. * * @param message the error message. * @param exception the exception that occurred. */ - public static void handleErrorCondition(String message, Exception exception) { + public static void handleErrorCondition(String message, Throwable exception) { + log.error(1, message, exception); handleErrorCondition(new InternalException(message, exception)); } @@ -99,33 +122,39 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { /** * Handle an error condition programmatically without throwing an exception. * This can be used in cases where recovery of the error is desirable. + *

+ * This method is guaranteed never to throw an exception, and can thus be safely + * used in finally blocks. * * @param exception the exception that occurred. */ - public static void handleErrorCondition(final Exception exception) { - final ExceptionHandler handler; - + public static void handleErrorCondition(final Throwable exception) { try { - - if (instance == null) { - handler = new ExceptionHandler(); - } else { - handler = instance; + if (!(exception instanceof InternalException)) { + log.error(1, "Error occurred", exception); } - final Thread thread = Thread.currentThread(); - + final ExceptionHandler handler = instance; + + if (handler == null) { + log.error("Error condition occurred before exception handling has been initialized", exception); + return; + } + if (SwingUtilities.isEventDispatchThread()) { + log.info("Running in EDT, showing dialog"); handler.showDialog(thread, exception); } else { - SwingUtilities.invokeAndWait(new Runnable() { + log.info("Not in EDT, invoking dialog later"); + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { handler.showDialog(thread, exception); } }); } } catch (Exception e) { - e.printStackTrace(); + log.error("Exception occurred in error handler", e); } } @@ -140,11 +169,12 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { // Out of memory if (isOutOfMemoryError(e)) { - JOptionPane.showMessageDialog(null, - new Object[] { - "OpenRocket can out of available memory!", - "You should immediately close unnecessary design windows,", - "save any unsaved designs and restart OpenRocket!" + log.info("Showing out-of-memory dialog"); + JOptionPane.showMessageDialog(null, + new Object[] { + "OpenRocket is out of available memory!", + "You should immediately close unnecessary design windows,", + "save any unsaved designs and restart OpenRocket!" }, "Out of memory", JOptionPane.ERROR_MESSAGE); return; } @@ -156,42 +186,45 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { } // Unknown Error - if (!(e instanceof Exception)) { - JOptionPane.showMessageDialog(null, - new Object[] { - "An unknown Java error occurred:", - msg, - "You should immediately close unnecessary design windows,
" + - "save any unsaved designs and restart OpenRocket!" + if (!(e instanceof Exception) && !(e instanceof LinkageError)) { + log.info("Showing Error dialog"); + JOptionPane.showMessageDialog(null, + new Object[] { + "An unknown Java error occurred:", + msg, + "You should immediately close unnecessary design windows,
" + + "save any unsaved designs and restart OpenRocket!" }, "Unknown Java error", JOptionPane.ERROR_MESSAGE); return; } - + // Normal exception, show question dialog + log.info("Showing Exception dialog"); int selection = JOptionPane.showOptionDialog(null, new Object[] { "OpenRocket encountered an uncaught exception. This typically signifies " + - "a bug in the software.", + "a bug in the software.", "        " + msg + "", " ", "Please take a moment to report this bug to the developers.", "This can be done automatically if you have an Internet connection." - }, "Uncaught exception", JOptionPane.DEFAULT_OPTION, - JOptionPane.ERROR_MESSAGE, null, + }, "Uncaught exception", JOptionPane.DEFAULT_OPTION, + JOptionPane.ERROR_MESSAGE, null, new Object[] { "View bug report", "Close" }, "View bug report"); if (selection != 0) { // User cancelled + log.user("User chose not to fill bug report"); return; } // Show bug report dialog + log.user("User requested sending bug report"); BugReportDialog.showExceptionDialog(null, t, e); - } - + /** * Registers the uncaught exception handler. This should be used to ensure that * all necessary registrations are performed. @@ -217,13 +250,13 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { */ private static void reserveMemory() { memoryReserve = new byte[MEMORY_RESERVE]; - for (int i=0; i= 3 && - (buggyClass.equals(elements[0].getClassName()) || - buggyClass.equals(elements[1].getClassName()) || - buggyClass.equals(elements[2].getClassName()))) { - System.err.println("Ignoring Sun JRE bug 6828938: " + t); - return; - } + if (trace.length > 3 && + trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") && + trace[0].getMethodName().equals("restoreTransientFor") && + + trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") && + trace[1].getMethodName().equals("removeFromTransientFors") && + + trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") && + trace[2].getMethodName().equals("setModalBlocked")) { + log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t); + return true; } + } + + + /* + * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16. + */ + if (t instanceof ArrayIndexOutOfBoundsException) { + final String buggyClass = "sun.font.FontDesignMetrics"; + StackTraceElement[] elements = t.getStackTrace(); + if (elements.length >= 3 && + (buggyClass.equals(elements[0].getClassName()) || + buggyClass.equals(elements[1].getClassName()) || + buggyClass.equals(elements[2].getClassName()))) { + log.warn("Ignoring Sun JRE bug 6828938: " + + "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6828938): " + t); + return true; + } + } + + /* + * Detect and ignore bug 6561072 in Sun JRE 1.6.0_? + */ + if (t instanceof NullPointerException) { + StackTraceElement[] trace = t.getStackTrace(); - if (instance != null) { - instance.uncaughtException(Thread.currentThread(), t); + if (trace.length > 3 && + trace[0].getClassName().equals("javax.swing.JComponent") && + trace[0].getMethodName().equals("repaint") && + + trace[1].getClassName().equals("sun.swing.FilePane$2") && + trace[1].getMethodName().equals("repaintListSelection") && + + trace[2].getClassName().equals("sun.swing.FilePane$2") && + trace[2].getMethodName().equals("repaintSelection")) { + log.warn("Ignoring Sun JRE bug 6561072 " + + "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6561072): " + t); + return true; + } + } + + + /* + * Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others + */ + if (t instanceof IllegalStateException) { + StackTraceElement[] trace = t.getStackTrace(); + + if (trace.length > 1 && + trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") && + trace[0].getMethodName().equals("getBackBuffer")) { + log.warn("Ignoring Sun JRE bug 6933331 " + + "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6933331): " + t); + return true; + } + } + + /* + * Detect and ignore bug in Sun JRE 1.6.0_19 + */ + if (t instanceof NullPointerException) { + StackTraceElement[] trace = t.getStackTrace(); + + if (trace.length > 3 && + trace[0].getClassName().equals("sun.awt.shell.Win32ShellFolder2") && + trace[0].getMethodName().equals("pidlsEqual") && + + trace[1].getClassName().equals("sun.awt.shell.Win32ShellFolder2") && + trace[1].getMethodName().equals("equals") && + + trace[2].getClassName().equals("sun.awt.shell.Win32ShellFolderManager2") && + trace[2].getMethodName().equals("isFileSystemRoot")) { + log.warn("Ignoring Sun JRE bug " + + "(see http://forums.sun.com/thread.jspa?threadID=5435324): " + t); + return true; } } + + /* + * Detect Sun JRE bug in D3D + */ + if (t instanceof ClassCastException) { + if (t.getMessage().equals("sun.awt.Win32GraphicsConfig cannot be cast to sun.java2d.d3d.D3DGraphicsConfig")) { + log.warn("Ignoring Sun JRE bug " + + "(see http://forums.sun.com/thread.jspa?threadID=5440525): " + t); + return true; + } + } + + return false; } + @SuppressWarnings("unused") private static class InternalException extends Exception { public InternalException() { super(); } - + public InternalException(String message, Throwable cause) { super(message, cause); } - + public InternalException(String message) { super(message); } - + public InternalException(Throwable cause) { super(cause); }