Hi,

I am using org.biojava.utils.ChangeSupport in a application I'm writing. I noticed some odd behavior yesterday: some of my ChangeListeners would stop being notified after the program had been executing for a short while. After some false starts, I looked at the ChangeSupport source and discovered that it only maintains weak references to the ChangeListeners registered in it.

After looking through the mailing list archives, I understand why this is desirable in some instances (see http://www.biojava.org/pipermail/biojava-l/2000-December/000578.html). Unfortunately, it conflicts with a common java-event-handling idiom: the inner class event handler (anonymous or not). When you do something like this:

chgable.addChangeListener(new ChangeAdapter() {
    public void postChange(ChangeEvent ce) {
        doSomething();
    }
});

or this:

chgable.addChangeListener(new InnerChangeHandler());

where chgable uses ChangeSupport, it silently stops working shortly after the application starts up because the only reference to the event handler is the weak reference in the ChangeSupport object.

Since the WeakReference use is, on one hand, a reasonable solution to a memory-efficiency problem but, on the other hand, silently causes odd behavior in some instances, I propose that this should be documented. Something like this might be sufficient:

---
Warning: ChangeSupport only maintains weak references to registered ChangeListeners. This means that any ChangeListener registered to it will stop receiving change events (because it is garbage-collected) as soon as all other references to the ChangeListener go out of scope. Classes that use ChangeSupport are advised to document this, as it will make anonymous event handlers fail to behave as expected.
---


In addition to this, it might be reasonable to add a version of ChangeSupport that uses strong references for those who are aware of the risks and don't care. A quick-and-dirty version of such a class appears below.

Rhett

------ StrongRefChangeSupport.java ------

import org.biojava.utils.ChangeSupport;
import org.biojava.utils.ChangeListener;
import org.biojava.utils.ChangeType;

import java.util.Set;
import java.util.HashSet;

/**
 * An implementation of ChangeSupport that maintains strong references
 * to registered ChangeListeners.  This makes it suitable for use with
 * anonymous ChangeListeners, but introduces the potential for memory
 * leaks when a large object listens to a long-lived object.
 */
public class StrongRefChangeSupport extends ChangeSupport {
    private Set strongRefs;

    public StrongRefChangeSupport() {
        super();
        initStrongRefs();
    }

    public StrongRefChangeSupport(int initialSize) {
        super(initialSize);
        initStrongRefs();
    }

    public StrongRefChangeSupport(int initialSize, int delta) {
        super(initialSize, delta);
        initStrongRefs();
    }

    public StrongRefChangeSupport(Set unchanging) {
        super(unchanging);
        initStrongRefs();
    }

public StrongRefChangeSupport(Set unchanging, int initialSize, int delta) {
super(unchanging, initialSize, delta);
initStrongRefs();
}


    private void initStrongRefs() {
        strongRefs = new HashSet();
    }

    public void addChangeListener(ChangeListener cl, ChangeType ct) {
        super.addChangeListener(cl, ct);
        strongRefs.add(new Key(cl, ct));
    }

    public void removeChangeListener(ChangeListener cl, ChangeType ct) {
        super.removeChangeListener(cl, ct);
        strongRefs.remove(new Key(cl, ct));
    }

    private static class Key {
        private final ChangeListener cl;
        private final ChangeType ct;
        public Key(ChangeListener cl, ChangeType ct) {
            this.cl = cl;
            this.ct = ct;
        }

        public boolean equals(Object other) {
            if (!(other instanceof Key)) return false;
            Key oKey = (Key) other;
            return (oKey.cl == this.cl && oKey.ct == this.ct);
        }

        public int hashCode() {
            return cl.hashCode() + ct.hashCode();
        }
    }
}

------ StrongRefChangeSupport.java ------

--
Rhett Sutphin
Research Assistant (Software)
Coordinated Laboratory for Computational Genomics
  and the Center for Macular Degeneration
University of Iowa - Iowa City, IA 52242 - USA
4111 MEBRF - email: [EMAIL PROTECTED]

_______________________________________________
Biojava-l mailing list  -  [EMAIL PROTECTED]
http://biojava.org/mailman/listinfo/biojava-l

Reply via email to