-
Bug
-
Resolution: Unresolved
-
P4
-
1.4.2, 6
-
Fix Understood
-
generic, x86
-
generic, windows_xp
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();
}
}
}
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();
}
}
}