001package co.codewizards.cloudstore.core.bean; 002 003import static co.codewizards.cloudstore.core.util.AssertUtil.*; 004import static co.codewizards.cloudstore.core.util.ReflectionUtil.*; 005 006import java.beans.PropertyChangeEvent; 007import java.beans.PropertyChangeListener; 008import java.lang.ref.Reference; 009import java.lang.ref.ReferenceQueue; 010import java.lang.ref.WeakReference; 011import java.util.Collections; 012import java.util.IdentityHashMap; 013import java.util.Map; 014 015public class WeakPropertyChangeListener implements PropertyChangeListener { 016 private static ReferenceQueue<PropertyChangeListener> listenerRefQueue = new ReferenceQueue<PropertyChangeListener>(); 017 private static Map<Reference<PropertyChangeListener>, WeakPropertyChangeListener> listenerRef2WeakPropertyChangeListener = 018 Collections.synchronizedMap(new IdentityHashMap<Reference<PropertyChangeListener>, WeakPropertyChangeListener>()); 019 020 private final Object bean; 021 private final Object property; 022 private final WeakReference<PropertyChangeListener> listenerRef; 023 private boolean registered; 024 025 public WeakPropertyChangeListener(final Object bean, final PropertyChangeListener listener) { 026 this(bean, null, listener); 027 } 028 029 public WeakPropertyChangeListener(final Object bean, final Object property, final PropertyChangeListener listener) { 030 expunge(); 031 032 this.bean = assertNotNull(bean, "bean"); 033 this.property = property; 034 035 listenerRef = new WeakReference<PropertyChangeListener>(listener, listenerRefQueue); 036 listenerRef2WeakPropertyChangeListener.put(listenerRef, this); 037 } 038 039 @Override 040 public void propertyChange(final PropertyChangeEvent event) { 041 expunge(); 042 043 final PropertyChangeListener listener = listenerRef.get(); 044 if (listener != null) 045 listener.propertyChange(event); 046 } 047 048 private static void expunge() { 049 Reference<? extends PropertyChangeListener> ref; 050 while ((ref = listenerRefQueue.poll()) != null) { 051 final WeakPropertyChangeListener weakPropertyChangeListener = listenerRef2WeakPropertyChangeListener.remove(ref); 052 053 if (weakPropertyChangeListener != null) 054 weakPropertyChangeListener.removePropertyChangeListener(); 055 } 056 } 057 058 public synchronized void addPropertyChangeListener() { 059 if (registered) 060 return; 061 062 if (property != null) 063 invoke(bean, "addPropertyChangeListener", property, this); 064 else 065 invoke(bean, "addPropertyChangeListener", this); 066 067 registered = true; 068 } 069 070 public synchronized void removePropertyChangeListener() { 071 if (! registered) 072 return; 073 074 if (property != null) 075 invoke(bean, "removePropertyChangeListener", property, this); 076 else 077 invoke(bean, "removePropertyChangeListener", this); 078 079 registered = false; 080 } 081}