jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] Re: Referencing composite component attributes in child components outside of a tree traversal

From: Blake Sullivan <blake.sullivan_at_oracle.com>
Date: Fri, 17 Feb 2012 11:55:09 -0800

On 2/17/12 6:08 AM, Kito Mann wrote:
>
> On Thu, Feb 16, 2012 at 12:40 PM, Blake Sullivan
> <blake.sullivan_at_oracle.com <mailto:blake.sullivan_at_oracle.com>> wrote:
>
> On 2/16/12 5:09 AM, Kito Mann wrote:
>>
>>
>> On Wed, Feb 15, 2012 at 11:53 PM, Blake Sullivan
>> <blake.sullivan_at_oracle.com <mailto:blake.sullivan_at_oracle.com>> wrote:
>>
>> Maybe I'm misunderstanding this, but how is this different
>> than accessing any other potentially-EL-bound attribute in
>> JSF? EL-bound values can only be safely evaluated when the
>> component in question is in the correct context. This means
>> either:
>> a) During lifecycle processing
>> b) During a tree visit callback
>> c) During an invokeOnComponent callback (which is really just
>> a degenerate version of b)
>>
>> I agree that this is has always been a major usability
>> problem with JSF, but that's how JSF is. The code below with
>> findComponent() has always been wrong. Programmers should
>> not be calling findComponent() and then attempting to
>> evaluate potentially EL-bound values.
>>
>>
>> The difference here is that the EL variable is "cc". The
>> component is simply referring to one of its own properties, not a
>> backing bean, so a developer would expect that to work when
>> making an arbitrary call to the component.
> Unless this is the composite component implementor's own code,
> then I would argue that when getting a the disabled property in
> this case:
> 1) How does the caller know that the property is not EL-bound
> 2) How does the caller know that an EL-bound property is only
> bound to "cc"
> 3) How does the caller know that for a "cc" bound property, the
> property is bound to a property that is not itself EL-bound
> 4) If the caller knows all this, they probably know the actual
> expression in the first place
>
>
> So, I suppose the question is really whether or not we should support
> the ability to use findComponent() and evaluate the properties outside
> of a tree traversal.
We have never been able to support this in the general case, which is
why invokeOnComponent() was invented. We should improve the
documentation and should maybe throw an IllegalStateException when
attempting to evaluate EL attributes on a non-current component during
the development project stage.

To summarize:

For attribute retrieval, findComponent has three issues:
1) It has no way of establishing context
2) No way of executing code in a context even if 1) was fixed
3) Not exactly fast

visitTree has the following issues:
1) clientIds are a pain to deal with for application developers
2) problems with reentrancy (fixable with context management)
3) Can be slow, though faster in esssentially all cases than
invokeOnComponent, and can be faster than findComponent for bulk operations

The issue with clientIds is that portions of the clientId are an
implementation detail of the components and renderkit. The result is
that developers are not supposed to be hardcoding clientIds into their
code. Developers need a different kind of id that specifies context
like a clientId, but is standardized like a findComponent search
expression. Let's call this a contextId.

Given a contextId, we would like to be able to do the following:
1) Efficiently convert the contextId into an object capable of
establishing and tearing down the context for the component relatively
efficiently. This would require new component apis.
2) Add a function like findComponentInContext that may return a proxy
for the UIComponent executing in the context object from 1)
3) Since setting up and tearing down context on every attribute
retrieval is inefficient--framework managed context so that the current
context may be torn down lazily.

As I said, these problems have always existed, it is just that most
developers don't typically notice that their components are executing EL
in the wrong context until the same EL variables start returning
different results based on the context.

Calling UIComponent.pushComponentToEL() from application is a seriously
bad idea. It may be your only choice in this case, but you really want
the framework to manage the context for you.

- Blake Sullivan
> I've found that calling UIComponent.pushComponentToEL() works in some
> cases if you call it before accessing the component's properties.
> Perhaps that's the solution -- just manually call that method first.
>
>
>
> -- Blake Sullivan
>
>>
>> As a side issue, the differences and uses of clientIds, the
>> id attribute of a components, and what the JSF findComponent
>> documentation calls "search expressions" are extremely
>> important, but poorly understood, as this code shows:
>>
>> HtmlImputText input =
>> (HtmlImputText)facesContext.findComponent(clientId);
>>
>> The Mojarra source is similarly confused in some places.
>>
>>
>> True --- I understand the distinction, but it is difficult to get
>> across.
>>
>>
>>
>> -- Blake Sullivan
>>
>>
>> On 2/15/12 8:37 PM, Kito Mann wrote:
>>> Does anyone have any thoughts on this issue?
>>> ___
>>>
>>> Kito D. Mann | twitter: kito99 | Author, JSF in Action
>>> Virtua, Inc. | http://www.virtua.com | JSF/Java EE training
>>> and consulting
>>> http://www.JSFCentral.com - JavaServer Faces FAQ, news, and
>>> info | twitter: jsfcentral
>>> +1 203-404-4848 x3 <tel:%2B1%20203-404-4848%20x3>
>>>
>>> * Listen to the latest headlines in the JSF and Java EE
>>> newscast:
>>> http://blogs.jsfcentral.com/roller/editorsdesk/category/JSF+and+Java+EE+Newscast
>>> * Sign up for the JSFCentral newsletter:
>>> http://oi.vresp.com/?fid=ac048d0e17
>>>
>>>
>>>
>>> On Fri, Aug 19, 2011 at 6:11 PM, Kito Mann
>>> <kito.mann_at_virtua.com <mailto:kito.mann_at_virtua.com>> wrote:
>>>
>>>
>>> On Fri, Aug 19, 2011 at 3:31 PM, Leonardo Uribe
>>> <lu4242_at_gmail.com <mailto:lu4242_at_gmail.com>> wrote:
>>>
>>> Hi
>>>
>>> I have been thinking about this and it seems the
>>> missing part has to
>>> be with UIComponent.findComponent(String expr).
>>>
>>>
>>> Hmm.. Isn't the problem really that the ValueExpression
>>> implementations have no reference to the component for
>>> which they were created? If the expression knew which
>>> component it was created for, it could use that
>>> component to find the composite component parent (among
>>> other things).
>>>
>>> What if the spec said that setValueExpression() must use
>>> a "ComponentMethodExpression" instance that held a
>>> reference to the component for which the expression was
>>> created?
>>>
>>>
>>>
>>> I think it is possible to prevent this problem,
>>> doing some
>>> implementation specific tweaks, but from the user
>>> point of view, only
>>> an alternative like a visitTree receiving a
>>> findComponent expression
>>> is reasonable. It could be good to find some use
>>> cases where this
>>> improvement is useful, to support its addition to
>>> the spec.
>>>
>>>
>>> I ran into this when a client had implemented
>>> multi-field validation inside of a PostValidateEvent
>>> listener. The code uses findComponent() to query the
>>> properties of different input controls, and when I
>>> switched them over to composite components, this broke:
>>>
>>> HtmlImputText input =
>>> (HtmlImputText)facesContext.findComponent(clientId);
>>> if (input.isDisabled())
>>> {
>>> ....
>>> }
>>>
>>> (Nevermind the fact that using these types of casts
>>> isn't always the best idea.)
>>>
>>> Now, it so happens that clientId now refers to a
>>> composite component child, whereas before it referred to
>>> stand-along HtmlInputText component. This code now
>>> returns false when the #{cc.attrs.disabled} expression
>>> returns true, because cc evaluates to null.
>>>
>>> Even if we don't solve this for 2.2, the spec should
>>> mandate that implementations throw an exception or
>>> something in this case. This is something developers
>>> simply won't expect (I was certainly surprised).
>>>
>>>
>>> regards,
>>>
>>> Leonardo Uribe
>>>
>>> 2011/8/17 Kito Mann <kito.mann_at_virtua.com
>>> <mailto:kito.mann_at_virtua.com>>:
>>> > Hello everyone,
>>> >
>>> > I just ran into an issue where
>>> #{cc.attrs.property} expressions don't work
>>> > when referenced via properties of child components
>>> if they're not referenced
>>> > inside of a tree traversal. More information here:
>>> > https://issues.apache.org/jira/browse/MYFACES-3283
>>> (happens in both MyFaces
>>> > and Mojarra).
>>> >
>>> > Section 5.6.2.1 (Implicit Object ELResolver for
>>> Facelets and Programmatic
>>> > Access) of the spec states the following:
>>> >
>>> > cc -> the current composite component relative to
>>> > the declaring page in which the expression appears.
>>> >
>>> > Since "current composite component" usually means
>>> the current composite
>>> > being processed during a tree traversal, "cc" can
>>> return null when it's
>>> > referenced elsewhere (i.e. in an action listener);.
>>> >
>>> > I'm thinking that the "cc" implicit variable
>>> should return the parent
>>> > composite component in cases where no "current
>>> composite component" is
>>> > available.
>>> >
>>> > Thoughts?
>>> > ---
>>> > Kito D. Mann | twitter: kito99 | Author, JSF in Action
>>> > Virtua, Inc. | http://www.virtua.com | JSF/Java EE
>>> training and consulting
>>> > http://www.JSFCentral.com - JavaServer Faces FAQ,
>>> news, and info | twitter:
>>> > jsfcentral
>>> > +1 203-404-4848 x3 <tel:%2B1%20203-404-4848%20x3>
>>> >
>>> > * Listen to the latest headlines in the JSF and
>>> Java EE
>>> > newscast:
>>> http://blogs.jsfcentral.com/roller/editorsdesk/category/JSF+and+Java+EE+Newscast
>>> > * Keep up with the aftermath of the Oracle/Sun merger:
>>> > http://www.mergerspeak.com
>>> >
>>> >
>>>
>>>
>>>
>>
>>
>
>