JDK-4063022 : RFE: Awt ThreadGroup catches all UncaughtExceptions
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.1,1.1.2,1.1.6
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_2.5.1,solaris_10
  • CPU: generic,sparc
  • Submitted: 1997-07-04
  • Updated: 2002-01-15
  • Resolved: 2000-10-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 betaFixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
In certain circumstance you will want to use the uncaughtException method in
the ThreadGroup class to deal with all uncaught exceptions

However, the AWT event dispatch code appears to deal with all uncaught
exceptions originating from the AWT event dispatch thread and thereby 
stops them from propogating upto the ThreadGroup uncaughtException method.

The critical section of the awt is in src/java/awt/EventDispatchThread.java

      class EventDispatchThread extends Thread {
      ...
	      try {

		  ...process events off the AWT event queue inside a
		     try/catch block...

	      } catch (Throwable e) {
                  System.err.println(
                      "Exception occurred during event dispatching:");
                  e.printStackTrace();
              }
  

If you have a event handler method such as a listner any exeption raised 
in the users code which then generates an exception will be propergated
to the EventDispatchThread exception handler and not the ThreadGroup
handler.

In most cases this is acceptable behaviour however where someone wants
that bit more control and error recovery the awt routine gets in the way.


For a real world example in the attachments called DemoApp.java which is 
a standalone application that creates a thread group and a thread creates 
a frame with a textarea and button.

The Thread is run and then I've included a simple class to output the 
thread stack when the button is pressed. Here is an example of the 
output

Thread Group: system  Max Priority: 10
    Thread: Clock  Priority: 12 Daemon
    Thread: Idle thread  Priority: 0 Daemon
    Thread: Async Garbage Collector  Priority: 1 Daemon
    Thread: Finalizer thread  Priority: 1 Daemon
    Thread: AWT-Finalizer  Priority: 9 Daemon
    Thread Group: main  Max Priority: 10
        Thread: main  Priority: 5
        Thread: Screen Updater  Priority: 4
        Thread Group: DemoApp Main ThreadGroup  Max Priority: 10
            Thread: AWT-EventQueue-0  Priority: 5
            Thread: AWT-Input  Priority: 5
            Thread: AWT-Motif  Priority: 5

Notice that the thread group "DemoApp Main ThreadGroup" is the parent of
the AWT- threads so it would be possible to have exceptions propergate
upwards.

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin FIXED IN: merlin-beta INTEGRATED IN: merlin-beta
14-06-2004

EVALUATION Fix in Merlin. Name: ssR10077 Date: 11/28/2000 Now all exceptions are passed to ThreadGroup.uncaughtException(). User can create the subclass of ThreadGroup directly from the application, and when initialize AWT inside of it. Also programmatic way to do it is provided. It can be done through "awt.threadgroup" system property. I didn't provide the way for applet to install it's own ThreadGroup since looks like none needs it and security impact of this decision is unknown. There was a problems with this proposal. If exception is passed to ThreadGroup.uncaughtException() the corresponding thread is dead. But with new AWTAutoShutdown code it is no longer a problem. If we need EventDispatchThread again it restarts. This makes this fix hard to backport, since it heavily relays on AWTAutoShutdown code integrated in Merlin. ======================================================================
11-06-2004

WORK AROUND Exception will have to be caught in each event callback / Listner class before they go into the AWT.
11-06-2004

SUGGESTED FIX Either specify all the AWT specific exceptions that could be raised in the EventDispatchThread class rather than just anything Throwable or an even better method would be to add a method such as public void propergateExceptions() Which sets an internal flag that when true throw the execptions up the object hierarchy rather than catching them and just printing the stack. Name: ssR10077 Date: 11/28/2000 *** /tmp/geta17511 Tue Oct 24 16:20:56 2000 --- EventDispatchThread.java Tue Oct 24 15:34:46 2000 *************** *** 95,122 **** } public void run() { ! pumpEvents(new Conditional() { ! public boolean evaluate() { ! return true; ! } ! }); ! /* ! * This synchronized block is to secure that the event dispatch ! * thread won't die in the middle of posting a new event to the ! * associated event queue. It is important because we notify ! * that the event dispatch thread is busy after posting a new event ! * to its queue, so the EventQueue.dispatchThread reference must ! * be valid at that point. ! */ ! synchronized (theQueue) { ! theQueue.detachDispatchThread(); ! AWTAutoShutdown.getInstance().notifyThreadFree(this); ! } } void pumpEvents(Conditional cond) { pumpEvents(ANY_EVENT, cond); } void pumpEvents(int id, Conditional cond) { while (doDispatch && cond.evaluate()) { if (isInterrupted() || !pumpOneEvent(id)) { --- 95,126 ---- } public void run() { ! try { ! pumpEvents(new Conditional() { ! public boolean evaluate() { ! return true; ! } ! }); ! } finally { ! /* ! * This synchronized block is to secure that the event dispatch ! * thread won't die in the middle of posting a new event to the ! * associated event queue. It is important because we notify ! * that the event dispatch thread is busy after posting a new event ! * to its queue, so the EventQueue.dispatchThread reference must ! * be valid at that point. ! */ ! synchronized (theQueue) { ! theQueue.detachDispatchThread(); ! AWTAutoShutdown.getInstance().notifyThreadFree(this); ! } ! } } void pumpEvents(Conditional cond) { pumpEvents(ANY_EVENT, cond); } + void pumpEvents(int id, Conditional cond) { while (doDispatch && cond.evaluate()) { if (isInterrupted() || !pumpOneEvent(id)) { *************** *** 142,154 **** return false; // AppContext.dispose() interrupts all // Threads in the AppContext ! } catch (Throwable e) { if (!handleException(e)) { ! System.err.println( ! "Exception occurred during event dispatching:"); ! e.printStackTrace(); } return true; } } --- 146,162 ---- return false; // AppContext.dispose() interrupts all // Threads in the AppContext ! // Can get and throw only unchecked exceptions ! } catch (RuntimeException e) { if (!handleException(e)) { ! throw e; } return true; + } catch (Error e) { + if (!handleException(e)) { + throw e; + } + return true; } } *** /tmp/geta17505 Tue Oct 24 16:19:56 2000 --- SunToolkit.java Tue Oct 24 15:52:26 2000 *************** *** 28,33 **** --- 28,34 ---- import sun.awt.im.SimpleInputMethodWindow; import sun.awt.image.*; import sun.awt.font.NativeFontWrapper; + import java.lang.reflect.Constructor; public abstract class SunToolkit extends Toolkit implements WindowClosingSupport, WindowClosingListener, *************** *** 45,67 **** private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue"; public SunToolkit() { ! EventQueue eventQueue; ! String eqName = Toolkit.getProperty("AWT.EventQueueClass", ! "java.awt.EventQueue"); AWTAutoShutdown.notifyToolkitThreadBusy(); ! try { ! eventQueue = (EventQueue)Class.forName(eqName).newInstance(); ! } catch (Exception e) { ! System.err.println("Failed loading " + eqName + ": " + e); ! eventQueue = new EventQueue(); ! } ! AppContext appContext = AppContext.getAppContext(); ! appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); ! PostEventQueue postEventQueue = new PostEventQueue(eventQueue); ! appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue); } public abstract WindowPeer createWindow(Window target) --- 46,105 ---- private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue"; public SunToolkit() { ! /* If awt.threadgroup is set to class name the instance of ! * this class is created (should be subclass of ThreadGroup) ! * and EventDispatchThread is created inside of it ! * ! * If loaded class overrides uncaughtException instance ! * handles all uncaught exception on EventDispatchThread ! */ ! ThreadGroup threadGroup = null; ! String tgName = System.getProperty("awt.threadgroup", ""); AWTAutoShutdown.notifyToolkitThreadBusy(); ! if (tgName.length() != 0) { ! try { ! Constructor ctor = Class.forName(tgName). ! getConstructor(new Class[] {String.class}); ! threadGroup = (ThreadGroup)ctor.newInstance(new Object[] {"AWT-ThreadGroup"}); ! } catch (Exception e) { ! System.err.println("Failed loading " + tgName + ": " + e); ! } ! } ! Runnable initEQ = new Runnable() { ! public void run () { ! EventQueue eventQueue; ! ! String eqName = Toolkit.getProperty("AWT.EventQueueClass", ! "java.awt.EventQueue"); ! ! try { ! eventQueue = (EventQueue)Class.forName(eqName).newInstance(); ! } catch (Exception e) { ! System.err.println("Failed loading " + eqName + ": " + e); ! eventQueue = new EventQueue(); ! } ! AppContext appContext = AppContext.getAppContext(); ! appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); ! ! PostEventQueue postEventQueue = new PostEventQueue(eventQueue); ! appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue); ! } ! }; ! ! if (threadGroup != null) { ! Thread eqInitThread = new Thread(threadGroup, initEQ, "EventQueue-Init"); ! eqInitThread.start(); ! try { ! eqInitThread.join(); ! } catch (InterruptedException e) { ! e.printStackTrace(); ! } ! } else { ! initEQ.run(); ! } } public abstract WindowPeer createWindow(Window target) ======================================================================
11-06-2004

PUBLIC COMMENTS In certain circumstance you will want to use the uncaughtException method in the ThreadGroup class to deal with all uncaught exceptions However, the AWT event dispatch code appears to deal with all uncaught exceptions originating from the AWT event dispatch thread and thereby stops them from propogating upto the ThreadGroup uncaughtException method.
10-06-2004