/* * org.openmicroscopy.shoola.env.AbnormalExitHandler * *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.env; //Java imports import javax.swing.JOptionPane; //Third-party libraries import org.openmicroscopy.shoola.env.init.StartupException; //Application-internal dependencies import omero.log.LogMessage; import omero.log.Logger; import org.openmicroscopy.shoola.env.ui.UIFactory; import org.openmicroscopy.shoola.env.ui.UserNotifier; /** * Handles uncaught exceptions thrown in the AWT event-dispatch thread and in * the main thread. * The handling policy is very easy for now: notify the user, log the exception, * and quit the application. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author <br>Andrea Falconi      * <a href="mailto:a.falconi@dundee.ac.uk"> * a.falconi@dundee.ac.uk</a> * @version 2.2 * <small> * (<b>Internal version:</b> $Revision$ $Date$) * </small> * @since OME2.2 */ class AbnormalExitHandler { /** The sole instance. */ private static AbnormalExitHandler singleton; /** * Creates the singleton and sets up AWT exception relay. * This must be called by the container just once and before initialization * takes place. */ static void configure() { //Don't need check for singleton existence, //the container will call this only once. singleton = new AbnormalExitHandler(); AWTExceptionHanlder.register(); } /** * Notifies the user, logs the exception, and quits the application. * Called by the container if an unhandled exception is detected in the * main thread or by the {@link AbnormalExitHandler} if an exception is * detected in the AWT event-dispatch thread. * * @param t The exception that went unhandled. */ static void terminate(Throwable t) { singleton.doTermination(t); //TODO: use another policy for InternalError. This is thrown in the //case of a bug which doesn't compromise normal functioning "too much". //So in this case we can just notify the user and log the error. } /** * Indicates whether termination is already in progress. * Latches to true after the first call to the * {@link #doTermination(Throwable) doTermination} method. */ private boolean inProgress = false; /** Only used for the singleton. */ private AbnormalExitHandler() {} /** * Actual implementation of the {@link #terminate(Throwable) terminate} * method. * This method is thread-safe. An exception might go unhandled in more * then one thread (initialization is performed while the splash screen * is showing), so we have to take into account the possibility that * multiple threads call this method concurrently. * * @param t The exception that went unhandled. */ private synchronized void doTermination(Throwable t) { //We need to make sure calls to this method are serialized. //The synchronized keywork ensures that only one thread at //a time can proceed. However, the same thread is allowed //to call this method again -- locks are re-entrant, so in //the case of recursion the original caller would enter again. //So just exit to avoid possible infinite loops if another //exception is thrown by the user notifier dialog (see below). if (inProgress) System.exit(1); //First call, set termination flag in case this method is //called again. inProgress = true; //Now try to log. There may be no logger yet (or even no //container) if the exception was thrown at start up. LogMessage msg = new LogMessage(); msg.println("Abnormal termination due to an uncaught exception."); msg.print(t); Container c = Container.getInstance(); Logger logger = null; if (c != null) logger = c.getRegistry().getLogger(); if (logger != null) logger.fatal(this, msg); else System.err.println(msg); StringBuffer buffer = new StringBuffer(); buffer.append("An unforeseen error occurred, the application" + " will exit."); buffer.append("\n"); String message = msg.toString(); int length = message.length(); if (length > 200) length = 200; buffer.append(message.substring(0, length)); buffer.append("..."); try { UserNotifier un = UIFactory.makeUserNotifier(c); un.notifyError("Abnormal Termination", buffer.toString(), msg.toString()); } catch (Exception e) { JOptionPane.showMessageDialog(null, buffer.toString(), "Abnormal Termination", JOptionPane.ERROR_MESSAGE); } //Quit the app. System.exit(1); } }