001package jmri.util.exceptionhandler;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004
005import java.awt.GraphicsEnvironment;
006
007import jmri.util.swing.ExceptionContext;
008
009/**
010 * Class to log exceptions that rise to the top of threads, including to the top
011 * of the AWT event processing loop.
012 *
013 * Using code must install this with
014 * <pre>
015 * Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
016 * </pre>
017 *
018 * @author Bob Jacobsen Copyright 2003, 2010
019 */
020public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
021
022    @Override
023    public void uncaughtException(Thread t, Throwable e) {
024
025        // see http://docs.oracle.com/javase/7/docs/api/java/lang/ThreadDeath.html
026        // 
027        // The type ThreadDeath has been deprecated since version 20 and marked for removal
028        // and the warning cannot be suppressed in Java 21. But external libraries might
029        // throw the exception outside of JMRI control. So check the name of the exception
030        // instead of using "instanceof".
031        if ("java.lang.ThreadDeath".equals(e.getClass().getName())) {
032            log.info("Thread has stopped: {}", t.getName());
033            return;
034        }
035
036        log.error("Uncaught Exception caught by jmri.util.exceptionhandler.UncaughtExceptionHandler", e);
037
038        if (e instanceof Error) {
039            if (!GraphicsEnvironment.isHeadless()) {
040                jmri.util.swing.ExceptionDisplayFrame.displayExceptionDisplayFrame(null,
041                    new ErrorContext(e));
042            }
043            log.error("System Exiting");
044            systemExit();
045        }
046    }
047
048    @SuppressFBWarnings(value="DM_EXIT", justification="Errors should terminate the application")
049    protected void systemExit(){
050        System.exit(126);
051    }
052
053    private static class ErrorContext extends ExceptionContext {
054
055        public ErrorContext(@javax.annotation.Nonnull Throwable ex) {
056            super(ex, "", "");
057            this.prefaceString = Bundle.getMessage("UnrecoverableErrorMessage");
058        }
059
060        @Override
061        public String getTitle() {
062            return Bundle.getMessage("UnrecoverableErrorTitle");
063        }
064
065    }
066
067    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UncaughtExceptionHandler.class);
068
069}