package co.codewizards.cloudstore.core.bean;
import static co.codewizards.cloudstore.core.util.AssertUtil.*;
import static co.codewizards.cloudstore.core.util.ReflectionUtil.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
public class WeakPropertyChangeListener implements PropertyChangeListener {
private static ReferenceQueue<PropertyChangeListener> listenerRefQueue = new ReferenceQueue<PropertyChangeListener>();
private static Map<Reference<PropertyChangeListener>, WeakPropertyChangeListener> listenerRef2WeakPropertyChangeListener =
Collections.synchronizedMap(new IdentityHashMap<Reference<PropertyChangeListener>, WeakPropertyChangeListener>());
private final Object bean;
private final Object property;
private final WeakReference<PropertyChangeListener> listenerRef;
private boolean registered;
public WeakPropertyChangeListener(final Object bean, final PropertyChangeListener listener) {
this(bean, null, listener);
}
public WeakPropertyChangeListener(final Object bean, final Object property, final PropertyChangeListener listener) {
expunge();
this.bean = assertNotNull(bean, "bean");
this.property = property;
listenerRef = new WeakReference<PropertyChangeListener>(listener, listenerRefQueue);
listenerRef2WeakPropertyChangeListener.put(listenerRef, this);
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
expunge();
final PropertyChangeListener listener = listenerRef.get();
if (listener != null)
listener.propertyChange(event);
}
private static void expunge() {
Reference<? extends PropertyChangeListener> ref;
while ((ref = listenerRefQueue.poll()) != null) {
final WeakPropertyChangeListener weakPropertyChangeListener = listenerRef2WeakPropertyChangeListener.remove(ref);
if (weakPropertyChangeListener != null)
weakPropertyChangeListener.removePropertyChangeListener();
}
}
public synchronized void addPropertyChangeListener() {
if (registered)
return;
if (property != null)
invoke(bean, "addPropertyChangeListener", property, this);
else
invoke(bean, "addPropertyChangeListener", this);
registered = true;
}
public synchronized void removePropertyChangeListener() {
if (! registered)
return;
if (property != null)
invoke(bean, "removePropertyChangeListener", property, this);
else
invoke(bean, "removePropertyChangeListener", this);
registered = false;
}
}