So, its come up again.  Parameters and bindings.

Problem:  Component parameters (defined in a component 
specification) become instances of IBinding, and are 
assigned to properties of the bean, or are stored in a 
Map, accessible via getBinding(String).

This has proven to be counter-intuitive and just plain 
confusing.

Why is it this way?

To support parameters that are output.  Think of 
Foreach's value parameter, or any of the form components.

However, those are the minority.  I've let the concerns 
of the minority impact the majority usage.

A secondary concern is efficiency; with the proposed 
change, Tapestry will do a bit more work than previously.

What's the change?

Its a bunch of small changes, with far-reaching effects.

Currently (thru 2.0.1), the render() method does it 
all.  The render() method is responsible for accessing 
bindings and extracting values from them.  It performs 
the nuts and bolts of rendering (either using Java code 
directly, or by rendering using a template).  It does 
cleanup after the render.  It may use bindings to output 
values.


render() will be broken into two pieces.

Most of what render() does today will take place in a 
new method, renderComponent().

render() will be responsible for
1) setting properties from bindings
2) invoking renderComponent()
3) clearing properties set by bindings

Note that there is no "update" step here; component's 
will still be responsible for obtaining IBindings for 
output parameters if they want to produce output; this 
will occur from inside renderComponent().

If there is no property matching the parameter name, 
then step 1 will *not* be expected to updating 
anything.  The component will need to obtain the binding 
and dereference through it, as is done today.

The current behavior of assigning the binding to a 
property named <parameter-name>Binding will not change.  
This is desirable for output parameters.

Static bindings: Tapestry will recognize static bindings 
and will only set the property for the binding once 
(assuming there is a matching property).  It is not 
clear when this assignment will occur (probably during 
the first render).

Notice step #3:  Tapestry will ensure (using a finally 
block) that properties are cleared after renderComponent
() is invoked.  This is necessary to avoid memory leaks.

For debate:  should step #3 apply to scalar properties 
(boolean, int, double, etc.) or just to object 
properties?

For debate:  Tapestry can now automate the process of 
checking for required parameters ... that is, it can 
enforce that a binding exists and that the binding's 
value is non-null ... or should this check stay in 
component code?

Effects of this change:

There will be a small loss in efficiency.  Tapestry 
today is pretty frugal about bindings; there are places 
where having binding A keeps Tapestry from acquiring and 
dereferencing binding B.  In addition, when rewinding 
(an entire page, or just a single form) the components 
know to not bother with most bindings ... this is also 
lost.  Rule #1 means all sorts of properties will be set.

There is also the destabilizing effect of such a large 
change; there are about 40 components within Tapestry 
that will be affected and who knows how many in the 
Tapestry community.

The plus side is that the codebase will shrink a bit.  
For example, something like:

** BEFORE **

private IBinding fooBinding;
private SomeType staticFoo;

public IBinding getFooBinding()
{
  return fooBinding;
}

public void setFooBinding(IBinding binding)
{
  fooBinding = binding;
  if (binding.isStatic())
    staticFoo = (SomeType)binding.getValue("foo", 
SomeType.class);
}

public void render(....)
{
  ...
  SomeType foo = staticFoo;

  if (foo == null && fooBinding != null)
    foo = (SomeType)fooBinding.getValue("foo", 
SomeType.class);

  foo...

  ...
}


** AFTER **

private SomeType foo;

public void setFoo(SomeType value)
{
  foo = value;
}

public SomeType getFoo()
{
  return foo;
}

public void renderComponent(...)
{
  foo...
}
  

It should be pretty obvious that the new code is far 
more desirable.  Note that none of the gobbledygook 
about static bindings is needed anymore ... if its 
static, it is set once and not changed.  If it is 
dynamic, it is set before renderComponent() and cleared 
after.

I'm really warming up to this change.  Given that 
Tapestry is a component-based framework, it makes sense 
that making components easier to construct is a win on 
both the coding and marketing side of things.

So ... the final question is: when?  2.0.2, 2.0.3 ... or 
should this wait for the 2.1 series?

I think that folks who are nervous about this change can 
safely stay on 2.0.1 until these changes iron out.  
2.0.1 is not missing any features and doesn't have any 
terrible bugs.

I suspect this will take a release or two to iron out, 
much like how validation spanned 1.0.7 - 1.0.9.

So .... thoughts?

--
[EMAIL PROTECTED]

http://tapestry.sf.net

_______________________________________________
Tapestry-developer mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/tapestry-developer

Reply via email to