You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Nathan Kopp <na...@kopp.com> on 2005/05/09 08:01:29 UTC

Ideas regarding "rewind" issues

In the recent "which two items..." thread, I saw a few requests for "fixing"
the rewind process.  Here are my thoughts on the topic.

There are a number of aspects of form rewinding (or "replaying", as I like
to call it) that I think confuse people.

One big issue, I think, is the fact that form rendering, both for display
and for replay (rewind), is handled in a sequential process.  Despite the
fact that Tapestry is component-based, the rendering process feels very
script-like to me, since the state of the page and component properties is
continually changing as the render takes place, especially when looping is
involved.

By itself this isn't an issue, but when you couple this with the following
two aspects, things get confusing:

The first aspect is that, during the replay (rewind) of the page, the
component tree is rebuilt dynamically from business objects stored in
various places.  If the contents of the business objects are not exactly the
same during replay as during the initial rendering, and different form
components are built, then Tapestry gets mad.

Second, listeners fire _during_ the render instead of at the end of
rendering.  Other frameworks seem to fire all of their listeners at the end
of rendering.  This mid-render fire of listeners has some benefits and some
drawbacks.  Because the page and component properties are constantly
changing during the loop, the listener fires at the point in time when the
page and component properties are in a specific state.  The listener can
call the property getters to determine the state of the loop.  If we wait
until the end of the rendering process, this state will be lost.  Let's give
this benefit the name "listener-knows-page-state".  One huge drawback,
though, is that the listener can't make changes to anything that would
affect components lower in the page.  For example, if your "delete" button's
listener deletes the current row from the list, then your iterator will
break and the page crashes.  So, you're stuck with a big if-else-if
statement in the form's listener, which is neither pretty nor clean, and
defeats the purpose of putting listeners on the submit buttons.

So that's the problem... what are possible solutions?

To deal with the first aspect, we need client-persistent page and component
properties.  Fortunately, this is coming in Tapestry 4.0.  :-)  An
alternative would be to save the component tree state in the page (as
opposed to saving the state of the business objects that determine the
component state).  However, this alone wouldn't work, because the component
properties are basically always bound to business objects, so the business
objects had better be in their original state, or things won't work as
expected.  In other words, client-persistent properties are basically the
only way to solve that problem.  I agree with whoever suggested that
encryption be part of the out-of-box client-persistent properties for them
to be fully robust.  Maybe they even could be encrypted by default.

(Note that right now (with 3.0.x) we can fake client-persistent properties
by using hidden fields and DataSqueezers, but it is too easy to make
mistakes with this solution, and they require more work than they should.)

To deal with the second issue, I would suggest enhancing the listeners:
1) The biggest enhancement would be to allow delayed-firing of listeners.
When I put a listener on a button, I want to be able to specify that the
listener fires after replay (rewind) is complete.  A listener should be
allowed to be configured for immediate-fire or delayed-fire.  I think that
in the future, the default should be delayed-fire, but for now it would have
to be immediate-fire for backwards compatibility.  During rendering,
listeners scheduled for firing would be pushed into a FIFO queue and then
pulled out and fired (in order) after rendering is complete.  I think we
might need at least three possibilities:  a) fire immediately; b) fire after
parent component renders (for components stored within other components);
and c) fire after page renders.*
2) Allow parameters to be passed to listeners.  If we delay the firing of
listeners, we lose the "listener-knows-page-state" benefit mentioned
earlier.  If we allow parameters to be passed to listeners, we can restore
most of this benefit, even when using delayed-firing listeners.  When the
component renders, the current state of the listener's parameter values
would be stored in a List, and these would be retrieved later (after
rendering) when the listener actually fires.  Of course, the contents of
those objects could have changed during the rendering, but I think you'd
find that, in practice, this generally won't be a problem.  Plus, there
might be ways to identify parameters that are likely to be altered and issue
a warning.  Listener parameters could be configured in two ways:  a)
ActionLink-style where page replay (rewind) is necessary, and the values are
calculated during replay; or b) DirectLink-style where replay is not
necessary the values during the initial render are embedded in the page as
URL or form parameters.**
3) The usage of listener and their parameters should be consistent across
all components and services.  This could consolidate ActionLink and
DirectLink so that they're the same, but they use two different
parameter-passing configurations.
4) As a side note, I would like to see more flexibility for listeners in
general.  For example, I'd love to put an "onChange" listener directly onto
the PropertySelection component instead of using the submitOnChange flag and
then putting a messy if-else-if into my form's listener.  I'd love to see
many additional listener triggers on various components, with the
possibility of multiple listeners attached to a single component.

(*Note:  I'm not totally sure, but I think that with listener parameters,
the immediate-firing listeners would probably be unnecessary.  Comments?)
(**Note 2:  I think that both kinds of parameter-passing configurations are
necessary... I personally think that ActionLink, or something like it, still
has its place, even if it must be used with caution.)

Another possible enhancement would be to allow the application to try to
handle stale page submission in a graceful way.  Maybe the page could have a
method that would handle stale page errors (by implementing an interface).
The business logic in the page might be able to determine what the user is
trying to do and tell the framework how to gracefully continue processing
without issuing an error.  Or, the business logic might be able to direct
the user to a nice page with a nice context-specific error message.  Once we
find some common patterns for graceful handling of stale forms, these
patterns could be built into the framework.

Thoughts?  (Especially about delayed-firing listeners and listener
parameters.)

-Nathan


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Ideas regarding "rewind" issues

Posted by Nathan Kopp <nk...@mailshell.com>.
Don't forget LinkSubmit.  :-)

Also, what do you think about some of the other ideas?
1) Conistent parameters for all listeners, where the developer can choose
whether the parameters are encoded in the URL (like DirectLink "service
parameters") or computed during the rewind (like component properties).
(This idea is basically an extension of your "Improved Listener Methods in
Picasso" blog from April 13th.)
2) Consistent multiple event listeners for various components (such as an
"onChangeListener", an "onFocusListener", etc.), with the "defer" option and
parameters for every listener.

Even if these are good ideas, I realize that they probably wouldn't make it
into 4.0, and some are component enhancements as opposed to framework
enhancements.  But does anybody else have any thoughts on these?  Like?
Dislike?

For what its worth, I was just now reading a thread from back in May 2004
(in the dev mailing list archives) about delayed listeners.  ...they say
everything old is new again.  :-)

-Nathan


Howard Lewis Ship <hl...@gmail.com> wrote:
> I've just added a "defer" parameter to Submit and ImageSubmit.
>
> Once Tapestry automatically handles everything, there'll be a lot less
> for me to cover in my labs!
>
> On 5/9/05, Nathan Kopp <nk...@mailshell.com> wrote:
> > "Nathan Kopp" <na...@kopp.com> wrote...
> >
> > > (*Note:  I'm not totally sure, but I think that with listener
parameters,
> > > the immediate-firing listeners would probably be unnecessary.
Comments?)
> >
> > Commenting on my own thoughts (this won't make any sense unless you've
read
> > the original email completely)....


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Ideas regarding "rewind" issues

Posted by Howard Lewis Ship <hl...@gmail.com>.
I've just added a "defer" parameter to Submit and ImageSubmit.

Once Tapestry automatically handles everything, there'll be a lot less
for me to cover in my labs!

On 5/9/05, Nathan Kopp <nk...@mailshell.com> wrote:
> "Nathan Kopp" <na...@kopp.com> wrote...
> 
> > (*Note:  I'm not totally sure, but I think that with listener parameters,
> > the immediate-firing listeners would probably be unnecessary.  Comments?)
> 
> Commenting on my own thoughts (this won't make any sense unless you've read
> the original email completely)....
> 
> I just noticed that MindBridge's "For" component has a listener.  What does
> this listener do?  Depending on what it does, I think this listener might,
> in fact, need to be configured for immediate-fire for it to be useful.  So,
> it looks like we would probably want to keep immediate-firing listeners to
> provide the added page-rendering flexibility demonstrated by the "For"
> component.
> 
> -Nathan
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
> 


-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Ideas regarding "rewind" issues

Posted by Nathan Kopp <nk...@mailshell.com>.
"Nathan Kopp" <na...@kopp.com> wrote...

> (*Note:  I'm not totally sure, but I think that with listener parameters,
> the immediate-firing listeners would probably be unnecessary.  Comments?)

Commenting on my own thoughts (this won't make any sense unless you've read
the original email completely)....

I just noticed that MindBridge's "For" component has a listener.  What does
this listener do?  Depending on what it does, I think this listener might,
in fact, need to be configured for immediate-fire for it to be useful.  So,
it looks like we would probably want to keep immediate-firing listeners to
provide the added page-rendering flexibility demonstrated by the "For"
component.

-Nathan


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org