Hi Travis,
Thanks for your response.
Yes, it looks to me like on the first visit to the view, the ids are
generated via that getOrCreateUniqueId method (which calls
UIViewRoot.createUniqueId). That id is then stored persistently in the
component. But on the second view, how does the 3rd anonymous JSF tag in
a page know which UIComponent object to attach to? I'm guessing that it
simply calls createUniqueId, and gets back "_id3", then attaches to the
existing component with that id. But that fails horribly if something
like <c:if> is used to enclose JSF tags and the if-condition changes
between consecutive render phases.
Maybe it is simply an unstated requirement that a JSP page does not add
or remove JSF components between rendering passes; I am aware that c:if
has problems with JSF. But the existence of the
UIComponentTag.removeFormerChildren method seems to imply to me that it
*is* allowed and supported for the JSP page and the view tree to not match.
Regarding re-use of JSP tag objects: this is allowed by the JSP spec.
It's a performance optimisation to reduce the number of JSP tag objects
that need to be created. Once a tag's doEndTag method has been called it
is available for reuse; see the javadoc for class
javax.servlet.jsp.tagext.Tag.
As you can see UIComponentTag.doEndTag calls internalRelease(). But
strangely, members _id, _rendered and _binding are cleared only in
release(), not internalRelease(). Maybe that's a bug?
Regards,
Simon
Travis Reeder wrote:
I believe the id's are generated at the time the component is
instantiated which seems to occur in UIComponentTag.findComponent().
The corresponding code is:
//Child
String id = getOrCreateUniqueId(context);
_componentInstance = parent.findComponent(id);
if (_componentInstance == null)
{
_componentInstance = createComponentInstance(context, id);
setProperties(_componentInstance);
......
I've just been tracing through this stuff all day to figure out how to
assign id's properly from a tag.
One very peculiar thing that may be somewhat related is that while
trying to set id's from a tag, it appears that the Tag object itself
is reused? Because initially the id on the tag is the same id as the
previous occurence of the same tag on the same page.
ex: i had a log message in HtmlMessageTag.setFor(String) and i output
getId on the tag. The second occurence of the message tag had the
previous occurences id at this point. Is it supposed to be reused?
Travis
On 11/22/05, Simon Kitching <[EMAIL PROTECTED]> wrote:
Hi,
As part of my investigations of
http://issues.apache.org/jira/browse/MYFACES-856
I have found that I need to understand how a UIComponentTag finds its
corresponding component.
When a JSP page is processed, each time a jsf tag is encountered a
UIComponentTag instance is created, initialised with the tag attributes,
and then doStartTag is invoked.
On the first visit to a view, there is no problem: each UIComponentTag
simply creates its corresponding component.
However on a re-render the UIComponentTag has to locate the appropriate
UIComponent instance in the view (see method findComponent). It's
important that it does this correctly, as this is how components with
failed validation (whose value to render is stored in the component's
_submittedValue member) render their value into the correct place in the
response.
The UIComponentTag knows its parent tag, and its parent tag knows its
component. So far so good.
Now if the tag in question has an explicit id assigned by the user then
there's no problem: a search is done in the children of the parent tag's
component for a matching id.
But what happens if the tag has an auto-generated id?
It looks to me like the "reconnection" process then depends upon
UIViewRoot generating anonymous ids in exactly the same sequence as on
the first view.
Won't this fail horribly if on re-render of a page there are more or
less JSF tags present than there were previously? UIComponentTags will
then "find" the wrong UIComponents, potentially of completely the wrong
type for that tag.
The methods UIComponentTag.removeFormerChildren/removeFormerFacets are
in this class explicitly to handle cases where re-rendering of a view
finds that JSF components have been added or removed. I had assumed that
this was to handle JSTL c:if tags enclosing JSF tags in a page, and
similar situations. Is this not the case? Perhaps this is not supported
at all, and the removeFormerChildren method is there only to handle
cases where components were programmatically added?
Is this all perhaps related to the mysterious comment in
UIComponentBase.getClientId?
if (id == null)
{
//Although this is an error prone side effect, we
// automatically create a new id
//just to be compatible to the RI
Thanks in advance for any info,
Simon