PUBLIC OBJECT

Chaining Stateless Properties

In a recent post, I described how I implemented the observers for stateless properties. In this follow up I describe how to do observers for chained properties.

What's a chained property?
Suppose I'd like to bind a combo box to a customer's country. If the Customer bean has a getCountry() property, that's easy. But if the Country is only exposed via a series of getters like getBillingAddress().getCountry(), I bind to Customer#address and address#country in series. A chained property is created by composing multiple properties into one.

Implementing get() and set() is easy
I resolve each property in the chain using the value of one property as the bean for the next:

public class ChainedProperty<B,V> implements Property<B,V> {
  private final List<Property> propertyChain;
  public ChainedProperty(...) { ... }

  public V get(B bean) {
    _Object current = bean;_
    for (Property property : propertyChain) {
      _current = property.get(current);_
    }
    return (V)current;
  }

  public void set(B bean, V value) {
    _Object current = bean;_
    for (Iterator<Property> m = propertyChain.iterator(); m.hasNext(); ) {
     Property property = m.next();

      if (m.hasNext()) {
        _current = property.get(current);_
      } else {
        _ property.set(current, value);_
      }
    }
  }
  ...
}`</pre>**Implementation Plan for Chaining Observers**
  1. Observe the bean for each property in the chain.

  2. When a property changes, action is required:
    Each time a new listener is registered on the chain, a new chain of SubListeners is created. Each SubListener observes a single property of a single bean. And so the chain of SubListeners observes the chain of properties. We use a custom SubListener at the end of the chain who notifies the PropertyChangeListener:

    `  public _abstract_ class SubListener<B, V> implements PropertyChangeListener {
        private final Property<B, V> property;
        private B bean;
        private V currentValue;
        public SubListener(...) { ... }
    
    void _setBean(B bean)_ {
      property.removePropertyChangeListener(bean, this);
      this.bean = bean;
      property.addPropertyChangeListener(bean, this);
      valueChanged();
    }
    
    public void propertyChange(PropertyChangeEvent evt) {
      valueChanged();
    }
    
    private void valueChanged() {
      V oldValue = currentValue;
      currentValue = property.get(bean);
      fireValueChanged(oldValue, currentValue);
    }
    
    abstract void _fireValueChanged(V oldValue, V currentValue)_;
    

    }

    public class ChainingSubListener<B, V> extends SubListener<B, V> {
    private final SubListener<V, ?> next;
    public ChainingSubListener(...) { ... }

    @Override
    public void fireValueChanged(V oldValue, V currentValue) {
      _next.setBean(currentValue);_
    }
    

    }

    public class LastSubListener<B, V> extends SubListener<B, V> {
    private final Object rootBean;
    private final String chainName;
    private final PropertyChangeListener delegate;
    public LastSubListener(...) { ... }

    @Override
    public void fireValueChanged(V oldValue, V currentValue) {
      _delegate.propertyChange(
          new PropertyChangeEvent(rootBean, chainName, oldValue, currentValue));_
    }
    

    }
    Removing Observers
    Just as with my previous solution, I can support removing the chain of listeners with a carefully crafted equals() method. Two SubListeners are equal if they model the same property, have the same chain of SubListeners downstream, and notify the same PropertyChangeListener at the chain's end.

ChainedProperty.java source listing