Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6467096

(prefs) unhandled exception stops Event Dispatch Thread

    XMLWordPrintable

    Details

    • Subcomponent:
    • Understanding:
      Fix Understood
    • CPU:
      generic, x86
    • OS:
      generic, windows_xp

      Description

      A DESCRIPTION OF THE FIX :
      Incident Number : 789415
        Bug Description : java.util.prefs.Preferences: unhandled exception stops Event Dispatch Thread
      Test case : See Test case section.
      Diff Baseline : JDK 6 b90
      Diff :
      diff -u -r old/java/util/prefs/AbstractPreferences.java new/java/util/prefs/AbstractPreferences.java
      --- old/java/util/prefs/AbstractPreferences.java 2006-07-17 13:43:19.000000000 +0300
      +++ new/java/util/prefs/AbstractPreferences.java 2006-09-04 12:03:45.288373800 +0300
      @@ -11,6 +11,8 @@
       import java.io.*;
       import java.security.AccessController;
       import java.security.PrivilegedAction;
      +import java.util.logging.Logger;
      +
       // These imports needed only as a workaround for a JavaDoc bug
       import java.lang.Integer;
       import java.lang.Long;
      @@ -1453,37 +1455,46 @@
           private static class EventDispatchThread extends Thread {
               public void run() {
                   while(true) {
      - // Wait on eventQueue till an event is present
      - EventObject event = null;
      - synchronized(eventQueue) {
      - try {
      + try {
      + EventObject event;
      + // Wait on eventQueue till an event is present
      + synchronized(eventQueue) {
                               while (eventQueue.isEmpty())
                                   eventQueue.wait();
                               event = (EventObject) eventQueue.remove(0);
      - } catch (InterruptedException e) {
      - // XXX Log "Event dispatch thread interrupted. Exiting"
      - return;
                           }
      - }
       
      - // Now we have event & hold no locks; deliver evt to listeners
      - AbstractPreferences src=(AbstractPreferences)event.getSource();
      - if (event instanceof PreferenceChangeEvent) {
      - PreferenceChangeEvent pce = (PreferenceChangeEvent)event;
      - PreferenceChangeListener[] listeners = src.prefListeners();
      - for (int i=0; i<listeners.length; i++)
      - listeners[i].preferenceChange(pce);
      - } else {
      - NodeChangeEvent nce = (NodeChangeEvent)event;
      - NodeChangeListener[] listeners = src.nodeListeners();
      - if (nce instanceof NodeAddedEvent) {
      - for (int i=0; i<listeners.length; i++)
      - listeners[i].childAdded(nce);
      + // Now we have event & hold no locks; deliver evt to listeners
      + AbstractPreferences src=(AbstractPreferences)event.getSource();
      + if (event instanceof PreferenceChangeEvent) {
      + PreferenceChangeEvent pce = (PreferenceChangeEvent)event;
      + PreferenceChangeListener[] listeners = src.prefListeners();
      + for (int i=0; i<listeners.length; i++) {
      + try {
      + listeners[i].preferenceChange(pce);
      + } catch (Throwable exc) {} // ignore, all listeners have to be notified
      + }
                           } else {
      - // assert nce instanceof NodeRemovedEvent;
      - for (int i=0; i<listeners.length; i++)
      - listeners[i].childRemoved(nce);
      + NodeChangeEvent nce = (NodeChangeEvent)event;
      + NodeChangeListener[] listeners = src.nodeListeners();
      + if (nce instanceof NodeAddedEvent) {
      + for (int i=0; i<listeners.length; i++) {
      + try {
      + listeners[i].childAdded(nce);
      + } catch (Throwable exc) {} // ignore, all listeners have to be notified
      + }
      + } else {
      + // assert nce instanceof NodeRemovedEvent;
      + for (int i=0; i<listeners.length; i++) {
      + try {
      + listeners[i].childRemoved(nce);
      + } catch (Throwable exc) {} // ignore, all listeners have to be notified
      + }
      + }
                           }
      + } catch (Throwable exc) {
      + // log only, event dispatch thread should work forever
      + Logger.getLogger("java.util.prefs").throwing(EventDispatchThread.class.getName(), "run()", exc);
                       }
                   }
               }


      JUnit TESTCASE :
      import java.util.prefs.*;

      import junit.framework.TestCase;

      public class PrefsEventTest extends TestCase {
      private static final long WAITING_TIME = 1000;
      private Preferences prefs;
      private boolean[] fired;
      private PreferenceChangeListener bad = new BadPreferenceChangeListener();

      public void setUp() throws Exception {
      prefs = Preferences.userRoot();
      fired = new boolean[2];
      prefs.addPreferenceChangeListener(new MockPreferenceChangeListener(fired, 0));
      prefs.addPreferenceChangeListener(bad);
      prefs.addPreferenceChangeListener(new MockPreferenceChangeListener(fired, 1));
      }

      public void tearDown() throws Exception {
      prefs.remove("a");
      }

      void checkNotification(String message) throws Exception {
      synchronized (fired) {
      long lastMoment = System.currentTimeMillis() + WAITING_TIME;
      assertTrue("overflow", lastMoment > 0);
      while (!fired[0] || !fired[1]) {
      long remains = lastMoment - System.currentTimeMillis();
      assertTrue(message + ": " +
      "event was not processed during waiting time (" + WAITING_TIME + " ms)," +
      " fired = [ " + fired[0] + ", " + fired[1] + " ]",
      remains > 0);
      fired.wait(remains);
      }
      }
      }

      public void testNotification() throws Exception {
      fired[0] = fired[1] = false;
      prefs.put("a", "b");
      checkNotification("Test 1"); // bad listener does not prevent all listeners to be notified
      prefs.removePreferenceChangeListener(bad);
      // once again
      fired[0] = fired[1] = false;
      prefs.put("a", "c");
      checkNotification("Test 2"); // bad listener does not terminate event dispatch thread
      }

      public static void main(String[] args) {
      junit.textui.TestRunner.run(PrefsEventTest.class);
      }

      }

      class BadPreferenceChangeListener implements PreferenceChangeListener {
      public void preferenceChange(PreferenceChangeEvent evt) {
      throw new RuntimeException();
      }
      }

      class MockPreferenceChangeListener implements PreferenceChangeListener {
      private final boolean[] fired;
      private final int index;

      MockPreferenceChangeListener(boolean[] fired, int index) {
      this.fired = fired; // copy reference, don't clone
      this.index = index;
      }

      public void preferenceChange(PreferenceChangeEvent evt) {
      synchronized (fired) {
      fired[index] = true;
      fired.notifyAll();
      }
      }
      }

        Attachments

          Activity

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            tbell Tim Bell
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Dates

              Created:
              Updated:
              Imported:
              Indexed: