EventDispatchExceptionHandler.java :  » Testing » abbot-1.0.1 » abbot » util » Java Open Source

Java Open Source » Testing » abbot 1.0.1 
abbot 1.0.1 » abbot » util » EventDispatchExceptionHandler.java
package abbot.util;

import java.awt.EventQueue;

import javax.swing.SwingUtilities;

import abbot.Log;

/** Handler for uncaught exceptions on any event dispatch thread.
    Once this has been installed, the class must be accessible by any
    subsequently launched dispatch thread.<p>

    This handler is installed by setting the System property
    sun.awt.exception.handler.  See javadoc for java.awt.EventDispatchThread
    for details.  This is sort of a patch to Sun's implementation, which only
    checks the property once and caches the result ever after.  This
    implementation will always chain to the handler indicated by the current
    value of the property.<p>

    It is most definitely NOT safe to try to install several of these on
    different threads.
 */
public class EventDispatchExceptionHandler {
    /** See javadoc for java.awt.EventDispatchThread. */
    public static final String PROP_NAME = "sun.awt.exception.handler";

    private static boolean installed = false;
    private static boolean canInstall = true;

    /** Install a handler for event dispatch exceptions.  This is kind
        of a hack, but it's Sun's hack.
        See the javadoc for java.awt.EventDispatchThread for details.
        NOTE: we throw an exception immediately, which 
        ensures that our handler is installed, since otherwise 
        someone might set this property later.
        java.awt.EventDispatchThread doesn't actually load the handler
        specified by the property until an exception is caught by the
        event dispatch thread.  SwingSet2 in 1.4.1 installs its own.
        Note that a new instance is created for each exception thrown.

        @throws RuntimeException if the handler cannot be installed.
        @throws IllegalStateException if this method is invoked from an event
        dispatch thread. 
        @throws IllegalArgumentException if the given class is not derived
        from this one. 

        // TODO: read the private static field
        // String EventDispatchThread.handlerClassName and override it if
        // necessary.
    */
    public void install() {
        if (SwingUtilities.isEventDispatchThread()) {
            throw new IllegalStateException("Handler must not be installed from the event dispatch thread");
        }

        Class cls = getClass();
        final String className = cls.getName();
        try {
            cls.newInstance();
        }
        catch(Exception e) {
            String msg = "Exception handler ("
                + cls + ") must have an accessible no-args Constructor: " + e;
            throw new IllegalArgumentException(msg);
        }
        if (installed) {
            // If we've already installed an instance of
            // this handler, all we need to do is set the
            // property name.
            Log.debug("Exception handler class already installed");
            System.setProperty(PROP_NAME, className);
        }
        else if (!canInstall) {
            Log.warn("Can't install event dispatch exception handler");
        }
        else {
            Log.log("Attempting to install handler " + className);
            class PropertiesHolder {
                /** Preserve the system properties state. */
                public java.util.Properties properties = null;
            }
            final PropertiesHolder holder = new PropertiesHolder();
            // Even if it's been set to something else, we can override it
            // if there hasn't been an event exception thrown yet.
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holder.properties = (java.util.Properties)
                        System.getProperties().clone();
                    // Set the property just before throwing the exception;
                    // OSX sets the property as part of AWT startup, so
                    // we have to override it here.
                    System.setProperty(PROP_NAME, className);
                    throw new DummyException();
                }
            });
            // Does nothing but wait for the previous invocation to finish
            AWT.invokeAndWait(new Runnable() { public void run() { } });
            System.setProperties(holder.properties);
            String oldHandler = System.getProperty(PROP_NAME);
            
            if (installed) {
                if (oldHandler != null) {
                    Log.debug("Replaced an existing event exception handler ("
                              + oldHandler + ")");
                }
            }
            else {
                canInstall = false;
                String msg = "The handler for event "
                    + "dispatch thread exceptions could not be installed";
                if (oldHandler != null) {
                    msg += " (" + oldHandler + " has already been "
                        + "set and cached; there is no way to override it)";
                }
                Log.warn(msg);
                throw new RuntimeException(msg);
            }
        }
    }

    /** Define this to handle the exception as needed.  
     * Default prints a warning to System.err.
     */
    protected void exceptionCaught(Throwable thrown) {
        System.err.println("Exception caught on event dispatch thread: " + thrown);
    }

    /** Handle exceptions thrown on the event dispatch thread. */
    public void handle(Throwable thrown) {
        Log.debug("Handling event dispatch exception: " + thrown);
        String handler = System.getProperty(PROP_NAME);
        boolean handled = false;
        if (handler != null && !handler.equals(getClass().getName())) {
            Log.debug("A user exception handler ("
                      + handler + ") has been set, invoking it");
            try {
                ClassLoader cl =
                    Thread.currentThread().getContextClassLoader();
                Class c = Class.forName(handler, true, cl);
                c.getMethod("handle", new Class[] { Throwable.class }).
                    invoke(c.newInstance(), new Object[] { thrown });
                handled = true;
            }
            catch(Throwable e) {
                Log.warn("Could not invoke user handler: " + e);
            }
        }
        // The exception may be created by a different class loader
        // so compare by name only
        if (thrown instanceof DummyException) {
            // Install succeeded
            Log.debug("Installation succeeded");
            installed = true;
        }
        else {
            if (!handled) {
                Log.debug("Handling exception on event dispatch thread: "
                          + thrown + " with " + getClass());
                Log.debug(thrown);
                exceptionCaught(thrown);
            }
        }
        Log.debug("Handling done");
    }

    public static boolean isInstalled() {
        return installed;
    }

    private static class DummyException extends RuntimeException {
        public String toString() {
            return super.toString() + " " + getClass().getClassLoader();
        }
    }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.