package org.archstudio.sysutils;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Creates a weak reference wrapper around a listener that automatically removes itself when the original listener is
* garbage collected.
*
* @author sahendrickson@gmail.com (Scott A. Hendrickson)
*/
public final class WeakListener {
/**
* Called to remove this listener from the event producer. Called when the original listener is garbage collected.
*
* @param <T>
* The proxy listener returned from
* {@link WeakListener#createWeakListener(Object, Class, RemoveListenerHandler)}.
*/
public static interface RemoveListenerHandler<T> {
/**
* Called to remove the proxy listener returned from
* {@link WeakListener#createWeakListener(Object, Class, RemoveListenerHandler)} from the event producer. Called
* when the original listener is garbage collected.
*
* @param proxyListener
*/
public void removeListener(T proxyListener);
}
/**
* Returns a proxy listener that should be added as a listener to the event producer. The original listener is
* wrapper in a weak reference. Once it is garbage collected, the {@link RemoveListenerHandler} is called to remove
* the proxy listener.
*
* @param originalListener
* The listener to wrap in a weak reference.
* @param ofType
* The type of the listener.
* @param removeListenerHandler
* The handler to call to remove the proxy listener when the original listener is garbage collected.
* @return The proxy listener that should be added as a listener to the event producer.
*/
@SuppressWarnings("unchecked")
public static final <T> T createWeakListener(T originalListener, Class<T> ofType,
final RemoveListenerHandler<T> removeListenerHandler) {
final WeakReference<T> weakReference = new WeakReference<T>(originalListener);
final T[] proxyObject = (T[]) Array.newInstance(ofType, 1);
proxyObject[0] =
(T) Proxy.newProxyInstance(ofType.getClassLoader(), new Class<?>[] { ofType }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
T listener = weakReference.get();
if (listener != null) {
return method.invoke(listener, args);
}
else {
removeListenerHandler.removeListener(proxyObject[0]);
return null;
}
}
});
return proxyObject[0];
}
}