Bogus behavior of window listeners

T

Twisted

I may have discovered another bug in the 1.6.0 release candidate
library implementation.

I mentioned earlier that my app's "are you sure?" on-exit dialog was
suddenly popping up twice. I've since found it popping up only once, as
it should, under a well-defined set of circumstances that prove the
culprit to be one of two occurrences of:

if (frame.getWindowListeners().length > 0)
frame.removeWindowListener(frame.getWindowListeners()[0]);

This used to work -- the window always has exactly the one window
listener if it has any, and it's sometimes removed and replaced with a
different one, and all of this activity is restricted to the event
dispatch thread so there are no concurrency issues.

Now we have a clear case of where this fails exactly once. The app adds
an initial window listener, and at a later time when there's some
cleanup to be done on exit it replaces that one with a different one.
If the cleanup stops being needed, it replaces it again. Although the
code in that replace is identical to the code in the first, I expect
javac is probably dumb enough to create two different anonymous inner
classes for these, so the third and the first aren't the same class as
the JVM sees it.

So listener 1 is added, then removed and 2 added, then 2 removed and 3
added, 3 removed and 2 added, 2 removed and 3 added, and so forth. Or
so it used to go. Now, one of them (perhaps listener 1) lingers
forever.

Either adding the first window listener doesn't cause
frame.getWindowListeners().length > 0, or
frame.removeWindowListener(frame.getWindowListeners()[0]) simply
doesn't work properly. I'm guessing the former -- add listener 1 and
the array remains empty; add listener 2 and it grows an element; remove
it and add listener 3 works as it should; remove that and put 2 back
works as it should; and so forth.

Anyone else encountering this?
 
A

Andrew Thompson

Twisted said:
I may have discovered another bug in the 1.6.0 release candidate
library implementation.

Bug ID?

(snip stuff about listeners and exit dialogs)
Anyone else encountering this?

Code?

(And why are you posting a very GUI related question
on c.l.j.programmer, rather than c.l.j.gui?)

Andrew T.
 
T

Twisted

Andrew said:
Bug ID?
?

(snip stuff about listeners and exit dialogs)


?

(And why are you posting a very GUI related question
on c.l.j.programmer, rather than c.l.j.gui?)

Because this is the c.l.j group I have bookmarked?
 
T

Thomas Hawtin

Twisted said:
I mentioned earlier that my app's "are you sure?" on-exit dialog was
suddenly popping up twice. I've since found it popping up only once, as
it should, under a well-defined set of circumstances that prove the
culprit to be one of two occurrences of:

if (frame.getWindowListeners().length > 0)
frame.removeWindowListener(frame.getWindowListeners()[0]);

You are assuming your listener is the only listener. That's not a good
assumption to make.
Now we have a clear case of where this fails exactly once. The app adds
an initial window listener, and at a later time when there's some
cleanup to be done on exit it replaces that one with a different one.
If the cleanup stops being needed, it replaces it again. Although the
code in that replace is identical to the code in the first, I expect
javac is probably dumb enough to create two different anonymous inner
classes for these, so the third and the first aren't the same class as
the JVM sees it.

Why not use a debugger or printf?

Tom Hawtin
 
T

Twisted

Thomas said:
Twisted said:
I mentioned earlier that my app's "are you sure?" on-exit dialog was
suddenly popping up twice. I've since found it popping up only once, as
it should, under a well-defined set of circumstances that prove the
culprit to be one of two occurrences of:

if (frame.getWindowListeners().length > 0)
frame.removeWindowListener(frame.getWindowListeners()[0]);

You are assuming your listener is the only listener. That's not a good
assumption to make.

In a part of the original posting that you conveniently snipped, I
explicitly stated that it is the only listener. I create the frame and
add just one. Later, under certain circumstances, code may remove it
and add a different one; again after that point there is only one.
There may be subsequent changes of the listener according to the same
pattern.
Why not use a debugger or printf?

Printf? In Java? :)

Well, actually I may take some further steps to investigate this. I
thought of putting a number in the title bar of the dialog box to
identify which listener is responsible for it. Then I'll know exactly
which one isn't being removed.
 
P

Patricia Shanahan

Twisted said:
Thomas Hawtin wrote: ....

Printf? In Java? :)

"printf" is a method in java.io.PrintStream, the class for both
System.err and System.out. It was added in 1.5.
Well, actually I may take some further steps to investigate this. I
thought of putting a number in the title bar of the dialog box to
identify which listener is responsible for it. Then I'll know exactly
which one isn't being removed.

Are you sure? Which one will your code display if you think you have
removed listener X, and have added listener Y?

I would be more direct about it, and put in a test for an existing
listener when one is about to be added.

Patricia
 
T

Thomas Hawtin

Twisted said:
In a part of the original posting that you conveniently snipped, I
explicitly stated that it is the only listener. I create the frame and

It's the only listener you add. It's not necessarily the only listener.
PL&F add listeners. Components add listeners to models. Lots of
listeners are about that you never knew about.
Printf? In Java? :)

Yeah, it's been in Java since 1.5 (I still use println myself).

Tom Hawtin
 
P

Patricia Shanahan

Thomas said:
It's the only listener you add. It's not necessarily the only listener.
PL&F add listeners. Components add listeners to models. Lots of
listeners are about that you never knew about.

However, presumably Twisted only cares about the explicitly created
listeners. Presumably, they will belong to user program classes,
including anonymous inner classes in the user program, not PL&F
implementation classes.

Patricia
 
P

Patricia Shanahan

Patricia said:
However, presumably Twisted only cares about the explicitly created
listeners. Presumably, they will belong to user program classes,
including anonymous inner classes in the user program, not PL&F
implementation classes.

I'm going to take that back. I just took another look at the base
message of this thread:

"if (frame.getWindowListeners().length > 0)
frame.removeWindowListener(frame.getWindowListeners()[0]);"

This code could be a really bad idea if there is ever a library
implementation listener attached to frame. Suppose the first element of
the array is a library listener, and the second is Twisted's. The
library listener gets removed, and Twisted's listener stays, as another
one is added.

I've never tried to remove an arbitrary listener, only ones I added, so
I have no practical experience of the effects of doing this.

Patricia
 
T

Twisted

Thomas said:
It's the only listener you add. It's not necessarily the only listener.
PL&F add listeners. Components add listeners to models. Lots of
listeners are about that you never knew about.

It worked before, so it seems doubtful that this could be the
explanation.
 
P

Patricia Shanahan

Twisted said:
It worked before, so it seems doubtful that this could be the
explanation.

The explanation that Thomas' observation suggests would lead to bugs
where any change in your program or the graphics libraries, even
apparently harmless changes, could matter.

You remove, in effect, an arbitrary Window listener, and then assume
that your listener has been removed.

The API documentation makes no statements about the order of listeners
in the array returned by getWindowListener, so the order could change,
for exactly the same combination of add and remove operations, from
release to release of the software. If your listener happens to be
referenced by element 0, all will be well. If not, you would get exactly
the symptoms you describe, plus possibly additional symptoms. There may
be consequences to the library failing to react to the condition the
removed listener was dealing with.

There is a really simple way to test for this issue. Change:

if (frame.getWindowListeners().length > 0)
frame.removeWindowListener(frame.getWindowListeners()[0]);

to

WindowListener[] listeners = frame.getWindowListeners();
if (listeners.length > 0){
if(listeners.length.length == 1){
frame.removeWindowListener(listeners[0]);
}else{
*** write debug output or throw an exception
}
}

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,270
Messages
2,571,102
Members
48,773
Latest member
Kaybee

Latest Threads

Top