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

[jsr344-experts] Re: [1080-ComponentContextId] Blake: request for help

From: Edward Burns <edward.burns_at_oracle.com>
Date: Fri, 16 Mar 2012 07:34:54 -0700

KM> So, I suppose the question is really whether or not we should support
KM> the ability to use findComponent() and evaluate the properties outside
KM> of a tree traversal.

B> We have never been able to support this in the general case, which is
B> why invokeOnComponent() was invented. We should improve the
B> documentation and should maybe throw an IllegalStateException when
B> attempting to evaluate EL attributes on a non-current component during
B> the development project stage.

EB> Ok, I've made the following change to the documentation to
EB> UIComponent.findComponent():
EB>
EB> Make the second paragraph of the javadoc for that method be:

EB> This method is not intended to be used with components that reside
EB> inside of an iterating component. To take action on a component inside
EB> of an iteration, or to find a component given a simple clientId, see
EB> invokeOnComponent.

B> It's actually more basic than that--you can't perform any operation on a
B> component returned by findComponent() that depends directly or
B> indirectly on the component being in the correct traversal context. In
B> practice, this means that attempting to retrieve an EL-bound attribute
B> value is not safe. Iteration is only the most obvious of these
B> problems, and the one that exists in the spec components.

Here is the revised text.

+ * <p class="changed_added_2_2">WARNING: The found
+ * <code>UIComponent</code> instance, if any, is returned
+ * <strong>without</strong> regard for its tree traversal context.
+ * Retrieving an EL-bound attribute from the component is not safe.
+ * EL expressions can contain implicit objects, such as
+ * <code>#{component}</code>, which assume they are being evaluated
+ * within the scope of a tree traversal context. Evaluating
+ * expressions with these kinds of implicit objects outside of a
+ * tree traversal context produces undefined results. See {_at_link
+ * #invokeOnComponent} for a method that <strong>does</strong>
+ * correctly account for the tree traversal context when operating
+ * on the found <code>UIComponent</code> instance. {_at_link #invokeOnComponent}
+ * is also useful to find components given a simple <code>clientId</code>.


EB> Now, to comply with your recommendation to throw an
EB> IllegalStateException, let's look at section "5.6.2 ELResolver for
EB> Facelets and Programmatic Access". In there, you see a diagram showing
EB> our ELResolver chain. Blake, would the following comply with your
EB> recommendation?

EB> Modify the table in section 5.6.2.1 so that for all ELResolver methods,
EB> if ProjectStage is development, and base is a UIComponent, throw an
EB> IllegalStateException if base is not equal to the component returned
EB> from UIComponent.getCurrentComponent()?

B> Yes. And this should also ensure that implementation code that needs to
B> mess with the current component, is doing so correctly.

I think there is another subtlety. Consider this expression

#{component.children[3].clientId}

That's a perfectly valid expression with respect to our assertion, but
when the EL resolution process gets around to "base is children[3]", the
assertion that the base is the current component will fail. But the
assertion should not fail because the context is, in fact, correct.
I've accounted for this in the implementation, and created UEL-29 into
the bargain.

Blake, I still need your help as requested earlier in the thread:

B> The issue with clientIds is that portions of the clientId are an
B> implementation detail of the components and renderkit. The result is
B> that developers are not supposed to be hardcoding clientIds into their
B> code. Developers need a different kind of id that specifies context
B> like a clientId, but is standardized like a findComponent search
B> expression. Let's call this a contextId.
EB>
B> Given a contextId, we would like to be able to do the following:
B> 1) Efficiently convert the contextId into an object capable of
B> establishing and tearing down the context for the component relatively
B> efficiently. This would require new component apis.
B> 2) Add a function like findComponentInContext that may return a proxy
B> for the UIComponent executing in the context object from 1)
B> 3) Since setting up and tearing down context on every attribute
B> retrieval is inefficient--framework managed context so that the current
B> context may be torn down lazily.

EB> Ahh, the tantalizingly succinct paragraph that seems like it addresses
EB> all my problems at first read, but at second read is shown to raise many
EB> more questions than it answers! I need some help in defining those "new
EB> component APIs" that Blake easily mentions in passing.

EB> I've filed 1080-ComponentContextId.

ACTION: Blake can you please sketch out what you mean by "new component
APIs"?

Thank you.

Ed

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage:               | http://ridingthecrest.com/