org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2009 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.internal.ide;

import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.IWorkbenchConfigurer;
import org.eclipse.ui.internal.ide.dialogs.InternalErrorDialog;
import org.eclipse.ui.progress.IProgressConstants;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.statushandlers.StatusAdapter;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;

import com.ibm.icu.text.MessageFormat;

/**
 * This is the IDE workbench error handler. The instance of this handler is
 * returned from IDEWorkbenchAdvisor#getWorkbenchErrorHandler(). All handled
 * statuses are checked against severity and logged using logging facility (by
 * superclass).
 * 
 * @since 3.3
 */
public class IDEWorkbenchErrorHandler extends WorkbenchErrorHandler {

    private int exceptionCount = 0;

    static private FatalErrorDialog dialog;

    private boolean closing = false;

    private IWorkbenchConfigurer workbenchConfigurer;

    // Pre-load all Strings trying to run as light as possible in case of fatal
    // errors.
    private static String MSG_OutOfMemoryError = IDEWorkbenchMessages.FatalError_OutOfMemoryError;

    private static String MSG_StackOverflowError = IDEWorkbenchMessages.FatalError_StackOverflowError;

    private static String MSG_VirtualMachineError = IDEWorkbenchMessages.FatalError_VirtualMachineError;

    private static String MSG_SWTError = IDEWorkbenchMessages.FatalError_SWTError;

    private static String MSG_FATAL_ERROR = IDEWorkbenchMessages.FatalError;

    private static String MSG_FATAL_ERROR_Recursive = IDEWorkbenchMessages.FatalError_RecursiveError;

    private static String MSG_FATAL_ERROR_Title = IDEWorkbenchMessages.InternalError;

    // cache handled statuses
    private final Map map = Collections.synchronizedMap(new WeakHashMap());

    /**
     * @param configurer
     */
    public IDEWorkbenchErrorHandler(IWorkbenchConfigurer configurer) {
        workbenchConfigurer = configurer;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.statushandlers.WorkbenchErrorHandler#handle(org.eclipse.ui.statushandlers.StatusAdapter,
     *      int)
     */
    public void handle(final StatusAdapter statusAdapter, int style) {

        // if fatal error occurs, we will show the blocking error dialog anyway
        if (isFatal(statusAdapter)) {
            // if we modify the hint, we have to be sure that status picked up
            // from .log will not be handled if it is reported independently via
            // StatusManager
            if (!map.containsKey(statusAdapter.getStatus())) {
                map.put(statusAdapter.getStatus(), null);
            } else {
                return;
            }
            if (statusAdapter.getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) == Boolean.TRUE) {
                statusAdapter.setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.FALSE);
            }
            super.handle(statusAdapter, style | StatusManager.BLOCK);
        } else {
            super.handle(statusAdapter, style);
        }

        // if fatal error occurs, we will ask to close the workbench
        if (isFatal(statusAdapter)) {
            UIJob handlingExceptionJob = new UIJob("IDE Exception Handler") //$NON-NLS-1$
            {
                /*
                 * (non-Javadoc)
                 * 
                 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
                 */
                public IStatus runInUIThread(IProgressMonitor monitor) {
                    handleException(statusAdapter.getStatus().getException());
                    return new Status(IStatus.OK, IDEWorkbenchPlugin.IDE_WORKBENCH,
                            IDEWorkbenchMessages.IDEExceptionHandler_ExceptionHandledMessage);
                }

            };

            handlingExceptionJob.setSystem(true);
            handlingExceptionJob.schedule();
        }
    }

    private boolean isFatal(final StatusAdapter statusAdapter) {
        if (statusAdapter.getStatus().getException() != null
                && (statusAdapter.getStatus().getException() instanceof OutOfMemoryError
                        || statusAdapter.getStatus().getException() instanceof StackOverflowError
                        || statusAdapter.getStatus().getException() instanceof VirtualMachineError
                        || statusAdapter.getStatus().getException() instanceof SWTError)) {
            return true;
        }
        return false;
    }

    private void handleException(Throwable t) {
        try {
            exceptionCount++;
            if (exceptionCount > 1) {
                dialog.updateMessage(
                        MessageFormat.format(MSG_FATAL_ERROR, new Object[] { MSG_FATAL_ERROR_Recursive }));
                dialog.getShell().forceActive();
            } else {
                if (openQuestionDialog(t)) {
                    closeWorkbench();
                }
            }
        } finally {
            exceptionCount--;
        }
    }

    /**
     * Informs the user about a fatal error. Returns true if the user decide to
     * exit workbench or if another fatal error happens while reporting it.
     */
    private boolean openQuestionDialog(Throwable t) {
        try {
            String msg = null;
            if (t instanceof OutOfMemoryError) {
                msg = MSG_OutOfMemoryError;
            } else if (t instanceof StackOverflowError) {
                msg = MSG_StackOverflowError;
            } else if (t instanceof VirtualMachineError) {
                msg = MSG_VirtualMachineError;
            } else if (t instanceof SWTError) {
                msg = MSG_SWTError;
            } else {
                if (t.getMessage() == null) {
                    msg = IDEWorkbenchMessages.InternalErrorNoArg;
                } else {
                    msg = NLS.bind(IDEWorkbenchMessages.InternalErrorOneArg, t.getMessage());
                }
            }

            // Always open the dialog in case of major error but do not show the
            // detail button if not in debug mode.
            Throwable detail = t;
            if (!Policy.DEBUG_OPEN_ERROR_DIALOG) {
                detail = null;
            }

            dialog = openInternalQuestionDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                    MSG_FATAL_ERROR_Title, MessageFormat.format(MSG_FATAL_ERROR, new Object[] { msg }), detail, 1);

            return dialog.open() == 0;
        } catch (Throwable th) {
            // Workbench may be in such bad shape (no OS handles left, out of
            // memory, etc)
            // that is cannot show a message to the user. Just bail out now.
            System.err.println("Error while informing user about event loop exception:"); //$NON-NLS-1$
            t.printStackTrace();
            System.err.println("Dialog open exception:"); //$NON-NLS-1$
            th.printStackTrace();
            return true;
        }
    }

    private FatalErrorDialog openInternalQuestionDialog(Shell parent, String title, String message,
            Throwable detail, int defaultIndex) {
        String[] labels;
        if (detail == null) {
            labels = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL };
        } else {
            labels = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL,
                    IDialogConstants.SHOW_DETAILS_LABEL };
        }

        FatalErrorDialog dialog = new FatalErrorDialog(parent, title, null, // accept
                // the
                // default
                // window
                // icon
                message, detail, MessageDialog.QUESTION, labels, defaultIndex);
        if (detail != null) {
            dialog.setDetailButton(2);
        }
        return dialog;
    }

    /**
     * Closes the workbench and make sure all exceptions are handled.
     */
    private void closeWorkbench() {
        if (closing) {
            return;
        }

        try {
            closing = true;
            if (dialog != null && dialog.getShell() != null && !dialog.getShell().isDisposed()) {
                dialog.close();
            }
            //@see WorkbenchAdvisor#getWorkbenchConfigurer()
            if (workbenchConfigurer != null)
                workbenchConfigurer.emergencyClose();
        } catch (RuntimeException re) {
            // Workbench may be in such bad shape (no OS handles left, out of
            // memory, etc)
            // that is cannot even close. Just bail out now.
            System.err.println("Fatal runtime error happened during workbench emergency close."); //$NON-NLS-1$
            re.printStackTrace();
            throw re;
        } catch (Error e) {
            // Workbench may be in such bad shape (no OS handles left, out of
            // memory, etc)
            // that is cannot even close. Just bail out now.
            System.err.println("Fatal error happened during workbench emergency close."); //$NON-NLS-1$
            e.printStackTrace();
            throw e;
        }
    }

    private class FatalErrorDialog extends InternalErrorDialog {

        /**
         * @param parentShell
         * @param dialogTitle
         * @param dialogTitleImage
         * @param dialogMessage
         * @param detail
         * @param dialogImageType
         * @param dialogButtonLabels
         * @param defaultIndex
         */
        public FatalErrorDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
                Throwable detail, int dialogImageType, String[] dialogButtonLabels, int defaultIndex) {
            super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, detail, dialogImageType,
                    dialogButtonLabels, defaultIndex);
        }

        /**
         * Updates the dialog message
         * 
         * @param message
         *            new message
         */
        public void updateMessage(String message) {
            this.message = message;
            this.messageLabel.setText(message);
            this.messageLabel.update();
        }
    }
}