[jsr-314-open] [NEW] <f:ajax> and <f:validateBean> - consistent wrapping solution needed?

Roger Kitain Roger.Kitain at SUN.COM
Tue Mar 10 10:52:35 EDT 2009


+1  - But I'm biased too...   ;-)

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>
>
> 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







More information about the jsr-314-open-mirror mailing list