Introduction

I recently completed an experimental project implementing “bound beans”, or a collection of beans which are wired up at run time so that some attribute changes on some of these beans result in other attribute changes on the same or a subset of the other beans. So, assume that had two instances of a hypothetical “Point” class with a couple of integer attributes named “x” and “y”, called “p0” and “p1”. Next, assume that these beans were bound to each other in such a way that setting some value to “p0.x” (by invoking “p0.setX(…)”) resulted in the same value being set into “p1.y”. Symbolically, you could express this binding relationship as “p0.x—>p1.y”. Now, you could throw an instance of a “Line” class into the mix (named “line”) , where the “Line” class contains two “Point” attributes named “start” and “end” (to represent the start and end points of a line, say). Further, you could specify an additional binding rule “p1.y—>line.start.x”. Then, setting “p0.x” results in the new value of this attribute cascading first to “p1.y”, and then to “line.start.x”.

The question is: what could you do with such a system?

Before tackling this question, however, let us look at an approach to implementing bean binding. The inputs to the the binding process are:

1. The bean instances which must be bound.

2. The binding relations (which I call “propagation rules”). The “source” of a propagation rule is the bean instance and its attribute that cause changes to occur in the same or other beans. For example, the “source” of the propagation rule “p0.x—>p1.y” is “p0.x”.

Pilot Implementation

My pilot implementation utilizes a Java agent to instrument some bean classes at load time in such a way that their “setXXX” methods are enhanced. The enhancement consists of invoking a static method call on a named “listener” class, passing the object (on which the “setXXX” method has been called) as a parameter. So, if the “setX” method of the “Point” class was originally:

public void setX(int x){

this.x = x;

}

its enhanced form is:

public void setX(int x){

this.x = x; // This is from the original version

com.subhajit.boundbeans.impl.Listener.attributeChanged(this);

}

The “Listener” class’s “attributeChanged” method knows which bean it is that has just been affected (from its argument, which is the “this” of the bean passed in via the call to “attributeChanged”). But how does it know which attribute of the bean has been affected? It simply creates a dummy RuntimeException, fills in its stack trace, and starts walking the stack trace elements down one by one until it reaches an element that was contributed by the class of the bean. From this element, it extracts the name of the method that was last called on the class of the bean (which, for a “Point” instance is going to be “setXXX”), from which, ultimately extracts the name of the bean attribute that has just been set).

Having determined both the bean instance that was affected and the particular attribute in the affected bean, the Listener class examines the propagation rules, looking for all rules in which the “source” (or the action that causes the rule to fire) is a change of this attribute on this bean. For all such rules, it determines the bean attributes (of the same or other) beans that are bound to the change in this attribute for this bean, and commences to set those attributes one by one. Of course, setting these attributes for the affected beans potentially triggers more updates (if target attribute being set on a target bean happens to be the “source” of another propagation rule).

Needless to say, I provide a facility to check for “cycles” that might intentionally or inadvertently arise in a set of propagation rules. The presence of cycles can potentially lead to “endless” property propagation resulting in an eventual StackOverflowError. For example, if the propagation rules specified are “p0.x—>p1.y” and “p1.y—>p0.x”, then changes to “p0.x” are propagated to “p1.y”, which are, in turn, propagated back to “p0.x”, to start the propagation cycle once again.

Applicability

To be honest, I cannot find myself coming up with a meaningful way to apply this “bean binding” facility. I can think of MVC GUI’s where setting a bean attribute in a model might propagate the value to a view (and vice versa) as one example of use. Can you help me with others?

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed

This blog copyright 2009 by Subhajit Dasgupta