com.raelity.org.openide.util
Class WeakListeners

java.lang.Object
  extended by com.raelity.org.openide.util.WeakListeners

public final class WeakListeners
extends Object

A generic weak listener factory. Creates a weak implementation of a listener of type lType. In the following examples, I'll use following naming:
There are four objects involved in weak listener usage:

The examples are written for ChangeListener. The Utilities have factory methods for the most common listeners used in NetBeans and also one universal factory method you can use for other listeners.

How to use it:

Here is an example how to write a listener/observer and make it listen on some source:
  public class ListenerObserver implements ChangeListener {
      private void registerTo(Source source) {
          source.addChangeListener(WeakListeners.changeListener (this, source));
      }

      public void stateChanged(ChangeEvent e) {
          doSomething();
      }
  }
 
You can also factor out the listener implementation to some other class if you don't want to expose the stateChanged method (better technique):
  public class Observer {
      private Listener listener;

      private void registerTo(Source source) {
          listener = new Listener();
          source.addChangeListener(WeakListeners.change (listener, source));
      }

      private class Listener implements ChangeListener {
          public void stateChanged(ChangeEvent e) {
              doSomething();
          }
      }
  }
 
Note: The observer keeps the reference to the listener, it won't work otherwise, see below.

You can also use the universal factory for other listeners:

  public class Observer implements SomeListener {
      private void registerTo(Source source) {
          source.addSomeListener((SomeListener)WeakListeners.create (
                  SomeListener.class, this, source));
      }

      public void someEventHappened(SomeEvent e) {
          doSomething();
      }
  }
 

How to not use it:

Here are examples of a common mistakes done when using weak listener:
  public class Observer {
      private void registerTo(Source source) {
          source.addChangeListener(WeakListeners.change(new Listener(), source));
      }

      private class Listener implements ChangeListener {
          public void stateChanged(ChangeEvent e) {
              doSomething();
          }
      }
  }
 
Mistake: There is nobody holding strong reference to the Listener instance, so it may be freed on the next GC cycle.
  public class ListenerObserver implements ChangeListener {
      private void registerTo(Source source) {
          source.addChangeListener(WeakListeners.change(this, null));
      }

      public void stateChanged(ChangeEvent e) {
          doSomething();
      }
  }
 
Mistake: The weak listener is unable to unregister itself from the source once the listener is freed. For explanation, read below.

How does it work:

The weak listener is used as a reference-weakening wrapper around the listener. It is itself strongly referenced from the implementation of the source (e.g. from its EventListenerList) but it references the listener only through WeakReference. It also weak-references the source. Listener, on the other hand, usually strongly references the observer (typically through the outer class reference). This means that:

  1. If the listener is not strong-referenced from elsewhere, it can be thrown away on the next GC cycle. This is why you can't use WeakListeners.change(new MyListener(), ..) as the only reference to the listener will be the weak one from the weak listener.
  2. If the listener-observer pair is not strong-referenced from elsewhere it can be thrown away on the next GC cycle. This is what the weak listener was invented for.
  3. If the source is not strong-referenced from anywhere, it can be thrown away on the next GC cycle taking the weak listener with it, but not the listener and the observer if they are still strong-referenced (unusual case, but possible).

Now what happens when the listener/observer is removed from memory:

This may fail if the source don't have the expected remove* method and/or if you provide wrong reference to source. In that case the weak listener instance will stay in memory and registered by the source, while the listener and observer will be freed.

There is still one fallback method - if some event come to a weak listener and the listener is already freed, the weak listener tries to unregister itself from the object the event came from.

Since:
4.10

Method Summary
static ChangeListener change(ChangeListener l, Object source)
          Creates a weak implementation of ChangeListener.
static
<T extends EventListener>
T
create(Class<T> lType, Class<? super T> apiType, T l, Object source)
          The most generic factory method to create weak listener for any listener interface that moreover behaves like a listener of another type.
static
<T extends EventListener>
T
create(Class<T> lType, T l, Object source)
          Generic factory method to create weak listener for any listener interface.
static DocumentListener document(DocumentListener l, Object source)
          Creates a weak implementation of DocumentListener.
static PropertyChangeListener propertyChange(PropertyChangeListener l, Object source)
          Creates a weak implementation of PropertyChangeListener.
static VetoableChangeListener vetoableChange(VetoableChangeListener l, Object source)
          Creates a weak implementation of VetoableChangeListener.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

create

public static <T extends EventListener> T create(Class<T> lType,
                                                 T l,
                                                 Object source)
Generic factory method to create weak listener for any listener interface.

Parameters:
lType - the type of listener to create. It can be any interface, but only interfaces are allowed.
l - the listener to delegate to, l must be an instance of lType
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
an instance of lType delegating all the interface calls to l.

create

public static <T extends EventListener> T create(Class<T> lType,
                                                 Class<? super T> apiType,
                                                 T l,
                                                 Object source)
The most generic factory method to create weak listener for any listener interface that moreover behaves like a listener of another type. This can be useful to correctly remove listeners from a source when hierarchies of listeners are used.

For example EventContext allows to add an instance of ObjectChangeListener but using method addNamingListener. Method removeNamingListener is then used to remove it. To help the weak listener support to correctly find the right method one have to use:

 ObjectChangeListener l = (ObjectChangeListener)WeakListeners.create (
   ObjectChangeListener.class, // the actual class of the returned listener
   NamingListener.class, // but it always will be used as NamingListener
   yourObjectListener,
   someContext
 );
 someContext.addNamingListener ("", 0, l);
 
This will correctly create ObjectChangeListener and unregister it by calling removeNamingListener.

Parameters:
lType - the type the listener shall implement. It can be any interface, but only interfaces are allowed.
apiType - the interface the returned object will be used as. It shall be equal to lType or its superinterface
l - the listener to delegate to, l must be an instance of lType
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
an instance of lType delegating all the interface calls to l.
Since:
4.12

propertyChange

public static PropertyChangeListener propertyChange(PropertyChangeListener l,
                                                    Object source)
Creates a weak implementation of PropertyChangeListener.

Parameters:
l - the listener to delegate to
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
a PropertyChangeListener delegating to l.

vetoableChange

public static VetoableChangeListener vetoableChange(VetoableChangeListener l,
                                                    Object source)
Creates a weak implementation of VetoableChangeListener.

Parameters:
l - the listener to delegate to
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
a VetoableChangeListener delegating to l.

document

public static DocumentListener document(DocumentListener l,
                                        Object source)
Creates a weak implementation of DocumentListener.

Parameters:
l - the listener to delegate to
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
a DocumentListener delegating to l.

change

public static ChangeListener change(ChangeListener l,
                                    Object source)
Creates a weak implementation of ChangeListener.

Parameters:
l - the listener to delegate to
source - the source that the listener should detach from when listener l is freed, can be null
Returns:
a ChangeListener delegating to l.