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 * This field is package-private so that the JRE cannot optimize its use away.
18 static volatile byte[] memoryReserve = null;
20 private static ExceptionHandler instance = null;
23 private volatile boolean handling = false;
29 public void uncaughtException(final Thread t, final Throwable e) {
31 // Free memory reserve if out of memory
32 if (isOutOfMemoryError(e)) {
42 System.err.println("Exception is currently being handled, ignoring:");
50 if (SwingUtilities.isEventDispatchThread()) {
53 SwingUtilities.invokeAndWait(new Runnable() {
60 } catch (Throwable ex) {
62 // Make sure the handler does not throw any exceptions
64 System.err.println("Exception in exception handler, dumping exception:");
66 } catch (Throwable ignore) { }
69 // Mark handling as completed
77 * Handle an error condition programmatically without throwing an exception.
78 * This can be used in cases where recovery of the error is desirable.
80 * @param message the error message.
82 public static void handleErrorCondition(String message) {
83 handleErrorCondition(new InternalException(message));
88 * Handle an error condition programmatically without throwing an exception.
89 * This can be used in cases where recovery of the error is desirable.
91 * @param message the error message.
92 * @param exception the exception that occurred.
94 public static void handleErrorCondition(String message, Exception exception) {
95 handleErrorCondition(new InternalException(message, exception));
100 * Handle an error condition programmatically without throwing an exception.
101 * This can be used in cases where recovery of the error is desirable.
103 * @param exception the exception that occurred.
105 public static void handleErrorCondition(final Exception exception) {
106 final ExceptionHandler handler;
110 if (instance == null) {
111 handler = new ExceptionHandler();
116 final Thread thread = Thread.currentThread();
118 if (SwingUtilities.isEventDispatchThread()) {
119 handler.showDialog(thread, exception);
121 SwingUtilities.invokeAndWait(new Runnable() {
123 handler.showDialog(thread, exception);
127 } catch (Exception e) {
134 * The actual handling routine.
136 * @param t the thread that caused the exception, or <code>null</code>.
137 * @param e the exception.
139 private void showDialog(Thread t, Throwable e) {
142 if (isOutOfMemoryError(e)) {
143 JOptionPane.showMessageDialog(null,
145 "OpenRocket can out of available memory!",
146 "You should immediately close unnecessary design windows,",
147 "save any unsaved designs and restart OpenRocket!"
148 }, "Out of memory", JOptionPane.ERROR_MESSAGE);
152 // Create the message
153 String msg = e.getClass().getSimpleName() + ": " + e.getMessage();
154 if (msg.length() > 90) {
155 msg = msg.substring(0, 80) + "...";
159 if (!(e instanceof Exception)) {
160 JOptionPane.showMessageDialog(null,
162 "An unknown Java error occurred:",
164 "<html>You should immediately close unnecessary design windows,<br>" +
165 "save any unsaved designs and restart OpenRocket!"
166 }, "Unknown Java error", JOptionPane.ERROR_MESSAGE);
171 // Normal exception, show question dialog
172 int selection = JOptionPane.showOptionDialog(null, new Object[] {
173 "OpenRocket encountered an uncaught exception. This typically signifies " +
174 "a bug in the software.",
175 "<html><em> " + msg + "</em>",
177 "Please take a moment to report this bug to the developers.",
178 "This can be done automatically if you have an Internet connection."
179 }, "Uncaught exception", JOptionPane.DEFAULT_OPTION,
180 JOptionPane.ERROR_MESSAGE, null,
181 new Object[] { "View bug report", "Close" }, "View bug report");
183 if (selection != 0) {
188 // Show bug report dialog
189 BugReportDialog.showExceptionDialog(null, t, e);
196 * Registers the uncaught exception handler. This should be used to ensure that
197 * all necessary registrations are performed.
199 public static void registerExceptionHandler() {
201 if (instance == null) {
202 instance = new ExceptionHandler();
203 Thread.setDefaultUncaughtExceptionHandler(instance);
205 // Handler for modal dialogs of Sun's Java implementation
206 // See bug ID 4499199.
207 System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());
216 * Reserve the buffer memory that is freed in case an OutOfMemoryError occurs.
218 private static void reserveMemory() {
219 memoryReserve = new byte[MEMORY_RESERVE];
220 for (int i=0; i<MEMORY_RESERVE; i++) {
221 memoryReserve[i] = (byte)i;
228 * Return whether this throwable was caused by an OutOfMemoryError
229 * condition. An exception is deemed to be caused by OutOfMemoryError
230 * if the throwable or any of its causes is of the type OutOfMemoryError.
232 * This method is required because Apple's JRE implementation sometimes
233 * masks OutOfMemoryErrors within RuntimeExceptions. Idiots.
235 * @param t the throwable to examine.
236 * @return whether this is an out-of-memory condition.
238 private boolean isOutOfMemoryError(Throwable t) {
240 if (t instanceof OutOfMemoryError)
250 * Handler used in modal dialogs by Sun Java implementation.
252 public static class AwtHandler {
253 public void handle(Throwable t) {
256 * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
258 if (t instanceof ArrayIndexOutOfBoundsException) {
259 final String buggyClass = "sun.font.FontDesignMetrics";
260 StackTraceElement[] elements = t.getStackTrace();
261 if (elements.length >= 3 &&
262 (buggyClass.equals(elements[0].getClassName()) ||
263 buggyClass.equals(elements[1].getClassName()) ||
264 buggyClass.equals(elements[2].getClassName()))) {
265 System.err.println("Ignoring Sun JRE bug 6828938: " + t);
271 if (instance != null) {
272 instance.uncaughtException(Thread.currentThread(), t);
278 private static class InternalException extends Exception {
279 public InternalException() {
283 public InternalException(String message, Throwable cause) {
284 super(message, cause);
287 public InternalException(String message) {
291 public InternalException(Throwable cause) {