6727884: Some Uncaught Exceptions are no longer getting sent to the Uncaught Exception Handlers
authorart
Thu, 11 Sep 2008 10:38:00 +0400
changeset 1961 436a5a828d9f
parent 1960 cc69c7cc3c58
child 1962 6c293d33645b
6727884: Some Uncaught Exceptions are no longer getting sent to the Uncaught Exception Handlers Reviewed-by: anthony, dav
jdk/src/share/classes/java/awt/EventDispatchThread.java
jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java
--- a/jdk/src/share/classes/java/awt/EventDispatchThread.java	Wed Sep 10 15:02:06 2008 +0400
+++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java	Thu Sep 11 10:38:00 2008 +0400
@@ -286,119 +286,19 @@
         }
         // Can get and throw only unchecked exceptions
         catch (RuntimeException e) {
-            processException(e, modalFiltersCount > 0);
+            processException(e);
         } catch (Error e) {
-            processException(e, modalFiltersCount > 0);
+            processException(e);
         }
         return true;
     }
 
-    private void processException(Throwable e, boolean isModal) {
+    private void processException(Throwable e) {
         if (eventLog.isLoggable(Level.FINE)) {
-            eventLog.log(Level.FINE, "Processing exception: " + e +
-                                     ", isModal = " + isModal);
-        }
-        if (!handleException(e)) {
-            // See bug ID 4499199.
-            // If we are in a modal dialog, we cannot throw
-            // an exception for the ThreadGroup to handle (as added
-            // in RFE 4063022).  If we did, the message pump of
-            // the modal dialog would be interrupted.
-            // We instead choose to handle the exception ourselves.
-            // It may be useful to add either a runtime flag or API
-            // later if someone would like to instead dispose the
-            // dialog and allow the thread group to handle it.
-            if (isModal) {
-                System.err.println(
-                    "Exception occurred during event dispatching:");
-                e.printStackTrace();
-            } else if (e instanceof RuntimeException) {
-                throw (RuntimeException)e;
-            } else if (e instanceof Error) {
-                throw (Error)e;
-            }
+            eventLog.log(Level.FINE, "Processing exception: " + e);
         }
-    }
-
-    private static final String handlerPropName = "sun.awt.exception.handler";
-    private static String handlerClassName = null;
-    private static String NO_HANDLER = new String();
-
-    /**
-     * Handles an exception thrown in the event-dispatch thread.
-     *
-     * <p> If the system property "sun.awt.exception.handler" is defined, then
-     * when this method is invoked it will attempt to do the following:
-     *
-     * <ol>
-     * <li> Load the class named by the value of that property, using the
-     *      current thread's context class loader,
-     * <li> Instantiate that class using its zero-argument constructor,
-     * <li> Find the resulting handler object's <tt>public void handle</tt>
-     *      method, which should take a single argument of type
-     *      <tt>Throwable</tt>, and
-     * <li> Invoke the handler's <tt>handle</tt> method, passing it the
-     *      <tt>thrown</tt> argument that was passed to this method.
-     * </ol>
-     *
-     * If any of the first three steps fail then this method will return
-     * <tt>false</tt> and all following invocations of this method will return
-     * <tt>false</tt> immediately.  An exception thrown by the handler object's
-     * <tt>handle</tt> will be caught, and will cause this method to return
-     * <tt>false</tt>.  If the handler's <tt>handle</tt> method is successfully
-     * invoked, then this method will return <tt>true</tt>.  This method will
-     * never throw any sort of exception.
-     *
-     * <p> <i>Note:</i> This method is a temporary hack to work around the
-     * absence of a real API that provides the ability to replace the
-     * event-dispatch thread.  The magic "sun.awt.exception.handler" property
-     * <i>will be removed</i> in a future release.
-     *
-     * @param  thrown  The Throwable that was thrown in the event-dispatch
-     *                 thread
-     *
-     * @return  <tt>false</tt> if any of the above steps failed, otherwise
-     *          <tt>true</tt>
-     */
-    private boolean handleException(Throwable thrown) {
-
-        try {
-
-            if (handlerClassName == NO_HANDLER) {
-                return false;   /* Already tried, and failed */
-            }
-
-            /* Look up the class name */
-            if (handlerClassName == null) {
-                handlerClassName = ((String) AccessController.doPrivileged(
-                    new GetPropertyAction(handlerPropName)));
-                if (handlerClassName == null) {
-                    handlerClassName = NO_HANDLER; /* Do not try this again */
-                    return false;
-                }
-            }
-
-            /* Load the class, instantiate it, and find its handle method */
-            Method m;
-            Object h;
-            try {
-                ClassLoader cl = Thread.currentThread().getContextClassLoader();
-                Class c = Class.forName(handlerClassName, true, cl);
-                m = c.getMethod("handle", new Class[] { Throwable.class });
-                h = c.newInstance();
-            } catch (Throwable x) {
-                handlerClassName = NO_HANDLER; /* Do not try this again */
-                return false;
-            }
-
-            /* Finally, invoke the handler */
-            m.invoke(h, new Object[] { thrown });
-
-        } catch (Throwable x) {
-            return false;
-        }
-
-        return true;
+        getUncaughtExceptionHandler().uncaughtException(this, e);
+        // don't rethrow the exception to avoid EDT recreation
     }
 
     boolean isDispatching(EventQueue eq) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java	Thu Sep 11 10:38:00 2008 +0400
@@ -0,0 +1,136 @@
+/*
+  @test
+  @bug 6304473 6727884
+  @summary Tests that an exception on EDT is handled with ThreadGroup.uncaughtException()
+  @author artem.ananiev: area=awt.eventdispatching
+  @library ../../regtesthelpers
+  @build Util
+  @run main HandleExceptionOnEDT
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+
+import test.java.awt.regtesthelpers.Util;
+
+public class HandleExceptionOnEDT
+{
+    private final static String EXCEPTION_MESSAGE = "A1234567890";
+
+    private static volatile boolean exceptionHandled = false;
+    private static volatile boolean mousePressed = false;
+
+    public static void main(String[] args)
+    {
+        final Thread.UncaughtExceptionHandler eh = new Thread.UncaughtExceptionHandler()
+        {
+            @Override
+            public void uncaughtException(Thread t, Throwable e)
+            {
+                if (e.getMessage().equals(EXCEPTION_MESSAGE))
+                {
+                    exceptionHandled = true;
+                }
+            }
+        };
+
+        Frame f = new Frame("F");
+        f.setBounds(100, 100, 400, 300);
+        // set exception handler for EDT
+        f.addWindowListener(new WindowAdapter()
+        {
+            @Override
+            public void windowOpened(WindowEvent we)
+            {
+                Thread edt = Thread.currentThread();
+                edt.setUncaughtExceptionHandler(eh);
+            }
+        });
+        f.setVisible(true);
+
+        Robot r = Util.createRobot();
+        Util.waitForIdle(r);
+
+        // check exception without modal dialog
+        MouseListener exceptionListener = new MouseAdapter()
+        {
+            @Override
+            public void mousePressed(MouseEvent me)
+            {
+                throw new RuntimeException(EXCEPTION_MESSAGE);
+            }
+        };
+        f.addMouseListener(exceptionListener);
+
+        exceptionHandled = false;
+        Point fp = f.getLocationOnScreen();
+        r.mouseMove(fp.x + f.getWidth() / 2, fp.y + f.getHeight() / 2);
+        Util.waitForIdle(r);
+        r.mousePress(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(r);
+        r.mouseRelease(InputEvent.BUTTON2_MASK);
+        f.removeMouseListener(exceptionListener);
+
+        if (!exceptionHandled)
+        {
+            throw new RuntimeException("Test FAILED: exception is not handled for frame");
+        }
+
+        // check exception with modal dialog
+        final Dialog d = new Dialog(f, "D", true);
+        d.setBounds(fp.x + 100, fp.y + 100, 400, 300);
+        d.addMouseListener(exceptionListener);
+        EventQueue.invokeLater(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                d.setVisible(true);
+            }
+        });
+        Util.waitForIdle(r);
+
+        exceptionHandled = false;
+        Point dp = d.getLocationOnScreen();
+        r.mouseMove(dp.x + d.getWidth() / 2, dp.y + d.getHeight() / 2);
+        Util.waitForIdle(r);
+        r.mousePress(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(r);
+        r.mouseRelease(InputEvent.BUTTON2_MASK);
+        d.removeMouseListener(exceptionListener);
+
+        if (!exceptionHandled)
+        {
+            throw new RuntimeException("Test FAILED: exception is not handled for modal dialog");
+        }
+
+        // check the dialog is still modal
+        MouseListener pressedListener = new MouseAdapter()
+        {
+            @Override
+            public void mousePressed(MouseEvent me)
+            {
+                mousePressed = true;
+            }
+        };
+        f.addMouseListener(pressedListener);
+
+        mousePressed = false;
+        r.mouseMove(fp.x + 50, fp.y + 50);
+        Util.waitForIdle(r);
+        r.mousePress(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(r);
+        r.mouseRelease(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(r);
+        f.removeMouseListener(pressedListener);
+
+        if (mousePressed)
+        {
+            throw new RuntimeException("Test FAILED: modal dialog is not modal or visible after exception");
+        }
+
+        // test is passed
+        d.dispose();
+        f.dispose();
+    }
+}