[jsr-314-open] composite:insertFacet target facet name

Andy Schwartz andy.schwartz at oracle.com
Thu Sep 24 22:04:10 EDT 2009


Hey Ken -

Ken Paulsen wrote:
>
>
> Andy Schwartz wrote:
>>
>> This raises a number of questions.  Why do we re-parent the facet 
>> component when we want the component to be used by the parent 
>> component as a facet,
> There is no way to add a facet without it being re-parented.  Perhaps 
> we should have changed the behavior to allow non-child components to 
> be facets of a component.

This stuff is so complicated.  I am lost already. :-)  Can you explain 
what you mean by "allow non-child components to be facets of a component"?
>
>> but not when we want the component to be used by the parent as a 
>> direct child?
> As you pointed out, there is no way to add a component from the page 
> to a component in the EZComp as a child (only as a facet).  If it were 
> possible, under the current JSF code, it too would be re-parented.

Right.  I was thinking that ideally composite:insertFacet would cover 
both the insert as a child case as well as the insert as a facet case 
(like ui:insert).

>>   Is there a reason why we need to treat the direct child case 
>> differently (not re-parent) than the facet case (re-parent)?  Is 
>> there some benefit to having subtly different behavior between these 
>> two cases?
> Yes, the not-reparent case is not a child.  It is an omission and were 
> it to be added,it too would re-parent (unless we changed the rules).
>
> The reason the 2 tags are treated differently is this:  1 modifies the 
> component tree; the other occurs during rendering.  Two very different 
> phases in JSF.

Sure.  That explains how these two tags are different, which I 
understand.  What I am still confused about is why these two cases 
needed to be handled differently.

>
> If we were to explore not re-parenting, we'd probably need to create a 
> ProxyComponent which could be added to the child and delegate 
> everything to the real component which would remain on the parent.  
> That might work nicely.

This sounds fairly close to what composite:renderFacet is doing, right?


>> While the first case inserts the component as a facet and the second 
>> as a direct child, both have the same semantics - ie. in both cases 
>> the component that is being inserted ends up as a child of the parent 
>> component that the child is being inserted into.
> Which is wrong.  The parent ideally should be the *composite 
> component*.  Keep in mind the template is a black box that the page 
> author should not know anything about.  So if I do:
>
>    <my:ezComponent id="foo">
>       <f:facet name="myfacet">
>             <h:outputText id="usercomp" value="here" />
>       </f:facet>
>    </my:ezComponent>
>
> So looking at this page excerpt, you'd say the parent of "usercomp" is 
> "foo".  And if foo is a naming container, the clientId would be 
> something like: "...:foo:usercomp".
>
> However, if the implementation of the ezcomp component (that the page 
> author has no control over and no know knowledge of) is implemented 
> like this:
>
>    ...
>    <some:namingcontainer id="hiddenContainer">
>       <ui:insert facet="myfacet" />
>    </some:namingcontainer>
>    ...
>
> Then we have problems:
>
> 1)  The parent is *not* "foo" as the page author expected (and as 
> would be the case with ALL Java-based components).
>
> 2) The clienId is not what we expected: 
> "...:foo:...:hiddenContainer:myfacet"
>
> 3) Changes that a component author makes to the component will break 
> any code the page author writes that depends on the location or 
> clientId of the facet component.
>

Right.  These are very similar to the issues that I was concerned about 
with #{cc} resolution.

Of course, we are already exposed to these issues with 
composite:insertFacet, eg:

<composite:implementation>
  <f:subview>
    <h:panelGrid>
      <composite:insertFacet name="caption"/>
    </h:panelGrid>
  </f:subview>
</composite:implementation>

I have mixed feelings about this.  When I wrote my previous mail, I 
suppose I was thinking that if we are going to be exposed to this 
behavior in both composite:insertFacet and ui:insert, then I would 
rather just be consistent and lose the composite:renderFacet behavior.  
But I understand your concerns about breaking the page author's (ie. 
composite component user's) abstraction.

Let me think this over some more.

FWIW, another issue that we haven't talked about is the potential for id 
collisions between components that the page author adds to the composite 
component vs. components that the composite component defines itself in 
its implementation.


> Now... was facelets wrong w/ ui:insert?  Absolutely not...  In 
> facelets they were not making components, they were making pages.  The 
> page author had visibility and full control of the UIComponent tree 
> structure that was being created.  VERY different than the component 
> scenario.

Okay, but just to be clear....  It sounds like your take is that the 
re-parenting behavior of <ui:insert> is (at least somewhat) acceptable, 
but this behavior in <composite:insertFacet> is wrong.   Is that right?


>   Which is likely why facelets was never able to create real components.
>
>> Actually, Facelets provides an API that is specifically designed to 
>> handle this type of insertion: TemplateClient.  The TemplateClient 
>> API allows for clean/efficient insertion of included content into 
>> templates.  I believe that ui:define/ui:insert use this to insert 
>> included content directly into the target location, avoiding the need 
>> to re-locate the included components from one parent to another.  
>> This has benefits when re-applying tags over a restored component 
>> tree, since there is no need to repeatedly re-create (or re-locate) 
>> these components.
> Not sure I follow you.  But I "think" you're describing meta-data that 
> represents the "files" which define the UIComponent tree (aka, VAST).  
> Which is something I have been advocating for and can greatly help.  
> However, once components are instantiated as UIComponents, they do 
> either have to be relocated, copied, or proxied (never seen this done 
> in practice)... so I think there's more to it than what you suggest.

There is definitely more to it.  My comment was pretty vague. :-)

I need to take a closer look at how tag handler re-execution is handled 
now that we've got partial state saving in place.  In the old days we 
used to re-execute tags (both JSP and Facelets) against the restored 
component tree on postbacks.  If components were moved around since the 
tags were originally executed, this could lead to complications when 
attempting to re-apply tags to an existing component tree - eg. subtrees 
that were moved from one parent to another might be re-populated, 
leading to unnecessary component creation.  The TemplateClient solution 
avoids this, since inserted component subtrees are only ever populated 
to one parent (the target of the insertion).

It is possible that this is no longer an issue.  I'll poke around and see.


>>
>> If we had the ability to revisit the design now, my preferred 
>> solution would be to:
>>
>> 1. Deprecate/remove composite:renderFacet.
>> 2. Re-spec composite:insertFacet to match the behavior of ui:insert.
> I think we could do this if we can also ensure that components are NOT 
> re-parented.  Then we could provide the correct behavior AND provide a 
> nice syntax for component authors.  However, I don't envy the person 
> (Ryan) that has to implement this. :)

I am amazed that Ryan doesn't hate me by now.  Well, I  hope not anyway. ;-)

>   There are a lot of tags and code that would have to have 
> special-case stuff to make this happen.

Yep.  So just to make sure I understand where you stand... Are you 
saying that you agree that we could handle these two cases:

<!-- Insert "foo" facet into the component tree as a facet -->
<composite:implementation>
 <h:panelGrid>
   <f:facet name="caption">
     <composite:insertFacet name="foo"/>
   </f:facet>
 </h:panelGrid>
</composite:implementation>


<!-- Insert "foo" facet into the component tree as a (non-facet) child -->
<composite:implementation>
 <h:panelGroup>
   <composite:insertFacet name="foo"/>
 </h:panelGroup>
</composite:implementation>


With a single tag?  But that you prefer that the tag does not actually 
perform re-parenting, ie. that the parent for the inserted component is 
the composite component itself in both cases?

FWIW, even if we do not have the ability to make changes along these 
lines now, I am still interested in understanding/working through these 
problems so that we have a firm grasp of any limitations/complications 
present in our current APIs.

Andy







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