001package co.codewizards.cloudstore.core.bean; 002 003import static co.codewizards.cloudstore.core.util.ReflectionUtil.*; 004import static co.codewizards.cloudstore.core.util.Util.*; 005import static java.util.Objects.*; 006 007import java.beans.PropertyChangeListener; 008import java.beans.PropertyChangeSupport; 009 010public class BeanSupport<B, P extends PropertyBase> { 011 private final B bean; 012 private final PropertyChangeSupport propertyChangeSupport; 013 014 public BeanSupport(final B bean) { 015 this.bean = requireNonNull(bean, "bean"); 016 propertyChangeSupport = new PropertyChangeSupport(bean); 017 } 018 019 public B getBean() { 020 return bean; 021 } 022 023 public void setPropertyValue(final P property, final Object value) { 024 requireNonNull(property, "property"); 025 026 final Object old; 027 synchronized (getMutex()) { 028 old = getFieldValue(bean, property.name()); 029 if (isEqual(property, old, value)) 030 return; 031 032 setFieldValue(bean, property.name(), value); 033 } 034 035 // We *must* fire the event *outside* of the *synchronized* block to make sure the listeners 036 // do not run into a dead-lock! 037 firePropertyChange(property, old, value); 038 } 039 040 public <V> V getPropertyValue(P property) { 041 synchronized (getMutex()) { 042 return getFieldValue(bean, property.name()); 043 } 044 } 045 046 protected Object getMutex() { 047 return bean; 048 } 049 050 protected boolean isEqual(final P property, final Object oldValue, final Object newValue) { 051 return equal(oldValue, newValue); 052 } 053 054 public void addPropertyChangeListener(final PropertyChangeListener listener) { 055 requireNonNull(listener, "listener"); 056 propertyChangeSupport.addPropertyChangeListener(listener); 057 } 058 059 public void removePropertyChangeListener(final PropertyChangeListener listener) { 060 requireNonNull(listener, "listener"); 061 propertyChangeSupport.removePropertyChangeListener(listener); 062 } 063 064 public void addPropertyChangeListener(final P property, final PropertyChangeListener listener) { 065 requireNonNull(property, "property"); 066 requireNonNull(listener, "listener"); 067 propertyChangeSupport.addPropertyChangeListener(property.name(), listener); 068 } 069 070 public void removePropertyChangeListener(final P property, final PropertyChangeListener listener) { 071 requireNonNull(property, "property"); 072 requireNonNull(listener, "listener"); 073 propertyChangeSupport.removePropertyChangeListener(property.name(), listener); 074 } 075 076 public void firePropertyChange(final P property, Object oldValue, Object newValue) { 077 requireNonNull(property, "property"); 078 propertyChangeSupport.firePropertyChange(property.name(), oldValue, newValue); 079 } 080}