1 package net.sf.openrocket.gui.main;
3 import javax.swing.JOptionPane;
4 import javax.swing.SwingUtilities;
6 import net.sf.openrocket.gui.dialogs.BugReportDialog;
9 public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
11 private static final int MEMORY_RESERVE = 512*1024;
14 * A memory reserve of 0.5 MB of memory, that can be freed when showing the dialog.
16 private static volatile byte[] memoryReserve = null;
18 private static ExceptionHandler instance = null;
21 private volatile boolean handling = false;
27 public void uncaughtException(final Thread t, final Throwable e) {
29 // Free memory reserve if out of memory
30 if (e instanceof OutOfMemoryError) {
40 System.err.println("Exception is currently being handled, ignoring:");
48 if (SwingUtilities.isEventDispatchThread()) {
51 SwingUtilities.invokeAndWait(new Runnable() {
58 } catch (Throwable ex) {
60 // Make sure the handler does not throw any exceptions
62 System.err.println("Exception in exception handler, dumping exception:");
64 } catch (Throwable ignore) { }
67 // Mark handling as completed
75 * Handle an error condition programmatically without throwing an exception.
76 * This can be used in cases where recovery of the error is desirable.
78 * @param message the error message.
80 public static void handleErrorCondition(String message) {
81 handleErrorCondition(new InternalException(message));
86 * Handle an error condition programmatically without throwing an exception.
87 * This can be used in cases where recovery of the error is desirable.
89 * @param message the error message.
90 * @param exception the exception that occurred.
92 public static void handleErrorCondition(String message, Exception exception) {
93 handleErrorCondition(new InternalException(message, exception));
98 * Handle an error condition programmatically without throwing an exception.
99 * This can be used in cases where recovery of the error is desirable.
101 * @param exception the exception that occurred.
103 public static void handleErrorCondition(final Exception exception) {
104 final ExceptionHandler handler;
108 if (instance == null) {
109 handler = new ExceptionHandler();
114 final Thread thread = Thread.currentThread();
116 if (SwingUtilities.isEventDispatchThread()) {
117 handler.showDialog(thread, exception);
119 SwingUtilities.invokeAndWait(new Runnable() {
121 handler.showDialog(thread, exception);
125 } catch (Exception e) {
132 * The actual handling routine.
134 * @param t the thread that caused the exception, or <code>null</code>.
135 * @param e the exception.
137 private void showDialog(Thread t, Throwable e) {
140 if (e instanceof OutOfMemoryError) {
141 JOptionPane.showMessageDialog(null,
144 "<html>You should immediately close unnecessary design windows,<br>" +
145 "save any unsaved designs and restart OpenRocket!"
146 }, "Out of memory", JOptionPane.ERROR_MESSAGE);
151 if (!(e instanceof Exception)) {
152 JOptionPane.showMessageDialog(null,
154 "An unknown Java error occurred:",
156 "<html>You should immediately close unnecessary design windows,<br>" +
157 "save any unsaved designs and restart OpenRocket!"
158 }, "Unknown Java error", JOptionPane.ERROR_MESSAGE);
163 // Normal exception, show question dialog
164 String msg = e.getClass().getSimpleName() + ": " + e.getMessage();
165 if (msg.length() > 90) {
166 msg = msg.substring(0, 90) + "...";
170 int selection = JOptionPane.showOptionDialog(null, new Object[] {
171 "OpenRocket encountered an uncaught exception. This typically signifies " +
172 "a bug in the software.",
173 "<html><em> " + msg + "</em>",
175 "Please take a moment to report this bug to the developers.",
176 "This can be done automatically if you have an Internet connection."
177 }, "Uncaught exception", JOptionPane.DEFAULT_OPTION,
178 JOptionPane.ERROR_MESSAGE, null,
179 new Object[] { "View bug report", "Close" }, "View bug report");
181 if (selection != 0) {
186 // Show bug report dialog
187 BugReportDialog.showExceptionDialog(null, t, e);
194 * Registers the uncaught exception handler. This should be used to ensure that
195 * all necessary registrations are performed.
197 public static void registerExceptionHandler() {
199 if (instance == null) {
200 instance = new ExceptionHandler();
201 Thread.setDefaultUncaughtExceptionHandler(instance);
203 // Handler for modal dialogs of Sun's Java implementation
204 // See bug ID 4499199.
205 System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());
213 private static void reserveMemory() {
214 memoryReserve = new byte[MEMORY_RESERVE];
215 for (int i=0; i<MEMORY_RESERVE; i++) {
216 memoryReserve[i] = (byte)i;
222 * Handler used in modal dialogs by Sun Java implementation.
224 public static class AwtHandler {
225 public void handle(Throwable t) {
228 * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
230 if (t instanceof ArrayIndexOutOfBoundsException) {
231 final String buggyClass = "sun.font.FontDesignMetrics";
232 StackTraceElement[] elements = t.getStackTrace();
233 if (elements.length >= 3 &&
234 (buggyClass.equals(elements[0].getClassName()) ||
235 buggyClass.equals(elements[1].getClassName()) ||
236 buggyClass.equals(elements[2].getClassName()))) {
237 System.err.println("Ignoring Sun JRE bug 6828938: " + t);
243 if (instance != null) {
244 instance.uncaughtException(Thread.currentThread(), t);
250 private static class InternalException extends Exception {
251 public InternalException() {
255 public InternalException(String message, Throwable cause) {
256 super(message, cause);
259 public InternalException(String message) {
263 public InternalException(Throwable cause) {