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

Alexander Smirnov asmirnov at exadel.com
Fri Sep 25 14:22:41 EDT 2009


The problem will be come if your render facet inside NamingContainer. 
For example, composite component:
* dataTable
   *column
    * panelGrid
        * facet "caption" : *reference* facet "myfacet"  <-- non-child facet
will not work without relocation. But, it would be even worse if you 
want to render facet more then once:
* dataTable
    * facet "caption" : *reference* facet "myfacet"
   *column
    * panelGrid
        * facet "caption" : *reference* facet "myfacet"


On 09/24/2009 10:17 PM, Ken Paulsen wrote:
>
>
> Andy Schwartz wrote:
>> 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"?
> Perhaps it's best to explain visually:
>
> Page author defines:
> * Page A
> * compComp
> * facet "myfacet" : component X <-- not a child of panelGrid
>
> Component author defines:
> * panelGrid
> * facet "caption" : *reference* facet "myfacet" <-- non-child facet
>
> So instead of re-parenting "component X" from "compComp" to "panelGrid",
> panelGrid maintains it's relationship that the page author defines.
> Today's behavior does the re-parenting as soon as you add it to the
> facet Map. A proxy-component might be possible that acts like a
> "symbolic link" to the page author's component so that the page author's
> original component doesn't get moved.
>>>> 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?
> Yes, but afaik, only for the "rendering" of the component. For example,
> if you ask for the "children" of the component put in as a place holder
> for rendering, I don't think you'll get the children defined by the page
> author... you'll get an empty list of children b/c there are no children
> of the placeholder itself.
>>>> 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.
> Yes, good point.
>>> 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?
> Yes, that's my current thinking. I see Facelets (and JSFTemplating)
> primarily as a way to construct UIComponent trees. So ui:insert is part
> of the templating language that pulls together component tree fragments
> in interesting ways.
>
> I do not believe that UIComponent tree changes should happen outside of
> the component which is added to the tree. The re-parenting that happens
> by composite:insertFacet causes the component tree that the page author
> specified to change. This breaks encapsulation of the component model.
>>> 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.
>> ;-)
> You should hear the things he says! Ok... not really. ;-) Not sure how
> he feels, but I appreciate your comments a lot. :)
>>> 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?
> Yes, that is what I was trying to say. I understand that may be much
> easier to *say* than implement, though, as it poses several challenges
> -- many of which I probably haven't thought through yet (such as how
> id's are resolved if it is inserted 2x or more).
>>
>> 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.
> I agree, I like to think through these things as well for the sake of
> understanding it better.
>
> Thanks!
>
> Ken
>>
>> Andy
>>
>>




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