001: /*******************************************************************************
002: * Copyright (c) 2003, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.ide;
011:
012: import com.ibm.icu.text.MessageFormat;
013:
014: import org.eclipse.jface.dialogs.IDialogConstants;
015: import org.eclipse.jface.dialogs.MessageDialog;
016: import org.eclipse.jface.window.Window;
017: import org.eclipse.osgi.util.NLS;
018: import org.eclipse.swt.SWT;
019: import org.eclipse.swt.SWTError;
020: import org.eclipse.swt.widgets.MessageBox;
021: import org.eclipse.swt.widgets.Shell;
022: import org.eclipse.ui.application.IWorkbenchConfigurer;
023: import org.eclipse.ui.internal.ide.dialogs.InternalErrorDialog;
024:
025: /**
026: * Handles exception while running the event loop.
027: * <p>
028: * In case of a "simpler" exception such as NPE, log the exception,
029: * open a dialog to inform the user and try to keep running.
030: * In case of a exception like OutOfMemory and SWTError, log the exception,
031: * open a dialog to ask the user to decide if the workbench should
032: * be terminated.
033: * </p>
034: */
035: public final class IDEExceptionHandler {
036:
037: private int exceptionCount = 0;
038:
039: private InternalErrorDialog dialog;
040:
041: private Shell defaultParent = new Shell();
042:
043: private boolean closing = false;
044:
045: private IWorkbenchConfigurer workbenchConfigurer;
046:
047: //Pre-load all Strings trying to run as light as possible in case of fatal errors.
048: private static String MSG_OutOfMemoryError = IDEWorkbenchMessages.FatalError_OutOfMemoryError;
049:
050: private static String MSG_StackOverflowError = IDEWorkbenchMessages.FatalError_StackOverflowError;
051:
052: private static String MSG_VirtualMachineError = IDEWorkbenchMessages.FatalError_VirtualMachineError;
053:
054: private static String MSG_SWTError = IDEWorkbenchMessages.FatalError_SWTError;
055:
056: private static String MSG_FATAL_ERROR = IDEWorkbenchMessages.FatalError;
057:
058: private static String MSG_FATAL_ERROR_Recursive = IDEWorkbenchMessages.FatalError_RecursiveError;
059:
060: private static String MSG_FATAL_ERROR_RecursiveTitle = IDEWorkbenchMessages.Internal_error;
061:
062: /**
063: * Creates the exception handle for the IDE application
064: *
065: * @param configurer an object for configuring the workbench
066: */
067: public IDEExceptionHandler(IWorkbenchConfigurer configurer) {
068: super ();
069: workbenchConfigurer = configurer;
070: }
071:
072: /**
073: * Handles an event loop exception
074: *
075: * @param t the exception to handle
076: */
077: public void handleException(Throwable t) {
078: try {
079: exceptionCount++;
080: if (exceptionCount > 1) {
081: if (closing) {
082: return;
083: }
084: Shell parent = defaultParent;
085: if (dialog != null && dialog.getShell() != null
086: && !dialog.getShell().isDisposed()) {
087: parent = dialog.getShell();
088: }
089: MessageBox box = new MessageBox(parent, SWT.ICON_ERROR
090: | SWT.YES | SWT.NO | SWT.SYSTEM_MODAL);
091: box.setText(MSG_FATAL_ERROR_RecursiveTitle);
092: box.setMessage(MessageFormat.format(MSG_FATAL_ERROR,
093: new Object[] { MSG_FATAL_ERROR_Recursive }));
094: int result = box.open();
095: if (result == SWT.YES) {
096: closeWorkbench();
097: }
098: } else {
099: if (openQuestionDialog(t)) {
100: closeWorkbench();
101: }
102: }
103: } finally {
104: exceptionCount--;
105: }
106: }
107:
108: /**
109: * Close the workbench and make sure all exceptions are handled.
110: */
111: private void closeWorkbench() {
112: if (closing) {
113: return;
114: }
115:
116: try {
117: closing = true;
118: if (dialog != null && dialog.getShell() != null
119: && !dialog.getShell().isDisposed()) {
120: dialog.close();
121: }
122: workbenchConfigurer.emergencyClose();
123: } catch (RuntimeException re) {
124: // Workbench may be in such bad shape (no OS handles left, out of memory, etc)
125: // that is cannot even close. Just bail out now.
126: System.err
127: .println("Fatal runtime error happened during workbench emergency close."); //$NON-NLS-1$
128: re.printStackTrace();
129: throw re;
130: } catch (Error e) {
131: // Workbench may be in such bad shape (no OS handles left, out of memory, etc)
132: // that is cannot even close. Just bail out now.
133: System.err
134: .println("Fatal error happened during workbench emergency close."); //$NON-NLS-1$
135: e.printStackTrace();
136: throw e;
137: }
138: }
139:
140: /**
141: * Inform the user about a fatal error. Return true if the user decide to
142: * exit workbench or if another fatal error happens while reporting it.
143: */
144: private boolean openQuestionDialog(Throwable internalError) {
145: try {
146: String msg = null;
147: if (internalError instanceof OutOfMemoryError) {
148: msg = MSG_OutOfMemoryError;
149: } else if (internalError instanceof StackOverflowError) {
150: msg = MSG_StackOverflowError;
151: } else if (internalError instanceof VirtualMachineError) {
152: msg = MSG_VirtualMachineError;
153: } else if (internalError instanceof SWTError) {
154: msg = MSG_SWTError;
155: } else {
156: if (internalError.getMessage() == null) {
157: msg = IDEWorkbenchMessages.InternalErrorNoArg;
158: } else {
159: msg = NLS.bind(
160: IDEWorkbenchMessages.InternalErrorOneArg,
161: internalError.getMessage());
162: }
163: if (Policy.DEBUG_OPEN_ERROR_DIALOG) {
164: return openQuestion(null,
165: IDEWorkbenchMessages.Internal_error, msg,
166: internalError, 1);
167: }
168: return false;
169: }
170: // Always open the dialog in case of major error but do not show the
171: // detail button if not in debug mode.
172: Throwable detail = internalError;
173: if (!Policy.DEBUG_OPEN_ERROR_DIALOG) {
174: detail = null;
175: }
176: return InternalErrorDialog.openQuestion(null,
177: IDEWorkbenchMessages.Internal_error, MessageFormat
178: .format(MSG_FATAL_ERROR,
179: new Object[] { msg }), detail, 1);
180: } catch (Throwable th) {
181: // Workbench may be in such bad shape (no OS handles left, out of memory, etc)
182: // that is cannot show a message to the user. Just bail out now.
183: System.err
184: .println("Error while informing user about event loop exception:"); //$NON-NLS-1$
185: internalError.printStackTrace();
186: System.err.println("Dialog open exception:"); //$NON-NLS-1$
187: th.printStackTrace();
188: return true;
189: }
190: }
191:
192: private boolean openQuestion(Shell parent, String title,
193: String message, Throwable detail, int defaultIndex) {
194: String[] labels;
195: if (detail == null) {
196: labels = new String[] { IDialogConstants.YES_LABEL,
197: IDialogConstants.NO_LABEL };
198: } else {
199: labels = new String[] { IDialogConstants.YES_LABEL,
200: IDialogConstants.NO_LABEL,
201: IDialogConstants.SHOW_DETAILS_LABEL };
202: }
203:
204: dialog = new InternalErrorDialog(parent, title, null, message,
205: detail, MessageDialog.QUESTION, labels, defaultIndex);
206:
207: if (detail != null) {
208: dialog.setDetailButton(2);
209: }
210: boolean result = dialog.open() == Window.OK;
211: dialog = null;
212: return result;
213: }
214: }
|