/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bushe.swing.exception; import java.io.PrintWriter; import java.io.StringWriter; import java.awt.Frame; import javax.swing.JDialog; /** * Plug this class into the AWT Thread to handle Exceptions. * In order to be used call either: * <pre> * java -Dsun.awt.exception.handler=org.bushe.swing.exception.AWTExceptionHandler * </pre> * or * <pre> * java -Dsun.awt.exception.handler=org.bushe.swing.exception.AWTExceptionHandler * </pre> * <p> * When this property is set, this class called by the EDT to handle * Exceptions encountered in the AWT Thread * <p> * This class is hopefully customizable enough for most any application. * <p> * @author Michael Bushe michael@bushe.com * @see java.awt.EventDispatchThread#handleException(Throwable) */ public class AWTExceptionHandler { private static String emailAddress; private static AWTErrorLogger logger; public static interface AWTErrorLogger { public void log(Throwable t); } public AWTExceptionHandler() { } /** * This returns null by default and if it returns null, no Email button is shown. * @return the current email address that the Email button on the error dialog will send to. */ public static String getErrorEmailAddress() { return emailAddress; } /** * If set to a non-null value, the Email button will be shown and will trigger the user's email * client to send an error email to the error email address. * @param emailAddy current email address that the Email button on the error dialog will send to. */ public static void setErrorEmailAddress(String emailAddy) { emailAddress = emailAddy; } /** * By default the handler logs errors to system.err. To log elsehwere, set an implementation of AWTErrorLogger, * probably wrapping your loggin implementation. */ public static void setLogger(AWTErrorLogger logger) { AWTExceptionHandler.logger = logger; } /** * Called by the AWT EventQueue to handle the exception. * @param t the throwable to handle */ public void handle(Throwable t) { Frame f = getFrameForMessageDialog(); if (f == null) { handleThrowableWithoutFrame(t); } else { handleThrowableWithFrame(f, t); } } /** * This method is called when there is no frame. Typically you will * log, but just prints to system.out. * @param t */ protected void handleThrowableWithoutFrame(Throwable t) { logError(t); } /** * This method is called when there is a frame. It pops up * the ErrorDialog with the message * @param t the throwable to handle */ protected void handleThrowableWithFrame(Frame f, Throwable t) { logError(t); JDialog dialog = createErrorDialog(f, t); dialog.pack(); dialog.setVisible(true); } /** * Logs the error the current implementation of the Logger. * @param t the throwable to log. */ protected void logError(Throwable t) { if (logger == null) { System.err.println(t); t.printStackTrace(System.err); } else { logger.log(t); } } /** * Creates an ErrorDialog. Feel free to override with yout own. * @param f the owning frame from getFrameForMessageDialog() * @param t the throwable to display * @return a dialog to show */ protected JDialog createErrorDialog(Frame f, Throwable t) { return new ExceptionDialog(f, t, false); } /** * Finds the frame for hte error message. * @return the best frame to use for placement of the error dialog */ protected Frame getFrameForMessageDialog() { Frame f = null; Frame[] frames = Frame.getFrames(); //Some possibly better schemes apps can use: //- Have each JFrame register with an active frame //-Have the exsception implement an interface that provides the associated component if (frames != null && frames.length > 0) { f = frames[0]; } return f; } /** * Given a throwable, it returns the stack trace as a string * @param t the throwable to processes * @return the Stack trace as it would look in t.printStackTrace() */ public static String stackTraceToString(Throwable t) { if (t == null) { return "No stack trace available."; } StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); t.printStackTrace(printWriter); printWriter.flush(); return stringWriter.getBuffer().toString(); } }