Hi Andy,
We did previously discuss this somewhere in the archive... (around
30th Oct)
On 10 Mar 2009, at 14:32, Andy Schwartz wrote:
Gang -
In JSF 2.0 we are introducing two core tags that wrap/enhance
component subtrees: f:ajax and f:validateBean.
f:ajax is used to enable Ajax behavior for a subtree, eg:
> <h:panelGroup>
> <!-- Turn on Ajax for the two input texts -->
> <f:ajax event="valueChange">
> <h:inputText value="foo"/>
> <h:inputText value="bar"/>
> </f:ajax>
> </h:panelGroup>
f:validateBean is used to enable bean validation for a subtree, eg:
> <h:panelGroup>
> <!-- Turn on bean validation for the two input texts -->
> <f:validateBean validationGroups="Group1, Group2"/>
> <h:inputText value="foo"/>
> <h:inputText value="bar"/>
> </f:validateBean>
> </h:panelGroup>
Actually, this isn't right. It would look like
<h:panelGroup>
<!-- Turn on bean validation for the two input texts -->
<f:validateBean validationGroups="Group1, Group2"/>
<h:inputText value="foo"/>
<h:inputText value="bar"/>
</h:panelGroup>
Which would enable validation for the whole panel group.
Having looked back at the previous messages, I think we went for the
nested element enables validation for the panel group on your advice
that this would unify us with f:ajax...
But this seems to be missing from the final Ajax design?
>
Of course, both tags can also be used in their nested form to enable
Ajax/bean validation on a single component.
We currently use different implementation strategies for the
"wrapping" behavior.
f:ajax uses a handler execution-time solution. AjaxHandler
maintains a stack that keeps track of the current nested state of
<f:ajax> tags. Before apply child handlers, AjaxHandler pushes the
current Ajax-related info onto this stack. When child/descendent
handlers are applied, ComponentTagHandlerDelegateImpl checks this
stack to get at the current Ajax-related state and performs the
necessary work to wire up an AjaxBehavior to the component.
Finally, after child handlers have been processed, AjaxHandler pops
the stack, and we're done.
The end result of the f:ajax solution is that once handlers have
finished executing, we have a fully configured component tree. No
further processing is necessary to apply "inherited" Ajax behavior.
f:validateBean uses a solution which is split between tag/handler
execution-time, validation-time and render-time.
BeanValidatorHandler/ValidatorTagHandlerDelegateImpl set up well
known properties on the parent component's attribute map (eg.
BeanValidator.VALIDATION_GROUPS_KEY,
UIInput.DEFAULT_VALIDATOR_IDS_KEY). These are used during later
lifecycle phases (eg. BeanValidator.validate(), UIInput.encodeEnd())
to determine which inherited validators to apply and how these
validators should be configured (eg. what validation groups to use).
The end result of the f:validateBean solution is that the handlers
only do part of the job - we need to do additional work during later
lifecycle phases to take advantage of the information that has been
stored away by the handlers.
While these two different strategies may at first seem like
implementation details, and thus not especially significant, the
choice of implementation does have impact on both our API and on
spec'ed behavior (or, on behavior that should be defined by the spec).
In terms of API, for f:validateBean the choice of implementation
leaks through a bit into the API in the form of the property keys
that are used to communicate between the handler implementations and
the component/validator implementations.
In terms of behavior, the different implementation strategies and up
with subtly different results which may cause confusion.
For example, in the following f:ajax case:
> <h:panelGroup>
>
> <!-- Turn Ajax on for this one -->
> <f:ajax event="valueChange">
> <h:inputText value="foo"/>
> </f:ajax>
>
> <!-- But not for this one -->
> <h:inputText value="bar"/>
>
> </h:panelGroup>
This should work as expected. That is, Ajax should be enabled for
the "foo" inputText, but not for the "bar" input text.
In a similar f:validateBean case:
> <h:panelGroup>
>
> <!-- Turn bean validation on for this one -->
> <f:validateBean validationGroups="Group1, Group2"/>
> <h:inputText value="foor"/>
> </f:validateBean>
>
> <!-- But not for this one -->
> <h:inputText value="bar"/>
>
> </h:panelGroup>
Unless I am missing something in the spec/implementation, I believe
that the validation-related properties are going to end up being
attached to the parent panelGroup when the BeanValidatorHandler is
applied. Which, if I understand this correctly, means that the
validation will be applied to both the "foo" and the "bar"
inputText. If this is the case, this is definitely not the desired
behavior.
I suspect that similar problems would arise when we've got multiple
<f:validateBean> under a single parent, eg:
> <h:panelGroup>
>
> <!-- Turn on Group1 validation for this one -->
> <f:validateBean validationGroups="Group1"/>
> <h:inputText value="foo"/>
> </f:validateBean>
>
> <!-- Turn on Group2 validation for this one -->
> <f:validateBean validationGroups="Group2"/>
> <h:inputText value="bar"/>
> <f:validateBean/>
>
> </h:panelGroup>
Though I haven't had a chance to test this out - just based on code
inspection seems like this would be a problem. (Though our <f:ajax>
implementation strategy handles this case just fine.)
Since there may be other subtle inconsistencies, it would make sense
to try to unify our implementation strategies across these two core
tags. Of course, I am biased towards the <f:ajax> approach. Seems
to have better behavior in terms of targeting only the wrapped
subtrees, has less exposure in the public API, and also just seems
cleaner to me to produce a fully configured component tree as a
result of handler execution.
Looking at the code, I didn't notice anything that would make it
difficult to re-factor the <f:validateBean> code to use a handler-
time strategy like <f:ajax>. I think our users would benefit from
the consistency. Any thoughts on whether we should/can go this
route? Did I miss anything in the <f:validteBean> behavior that
would prevent us from using a handler-time solution?
Andy
--
Pete Muir
http://www.seamframework.org
http://in.relation.to/Bloggers/Pete