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

Andy Schwartz andy.schwartz at oracle.com
Fri Sep 25 10:53:45 EDT 2009


Ken Paulsen wrote:
>  
> 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.

Got it.  The symbolic link analogy is good.

>>>
>>> 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.

Right.

>   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.

Yep.

>>
>> 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.

Cool.  I feel better now that we've sorted through this a bit. :-)

It seems to me that there are two parts of this problem:

- What the appropriate set of tags are to expose to composite component 
authors.
- What the appropriate implementation is for inserting facets components 
into composite implementation components.

As we've seen, the choice of #2 has impact on the page author.

Regarding #1... It seems like we agree that it would be desirable to 
have a single tag that can perform three operations:

1. Insert a facet into the composite implementation as a facet of an 
arbitrary component using the same facet name.
2. Insert a facet into the composite implementation as a facet of an 
arbitrary component using a different facet name.
3. Insert a facet into the composite implementation as a direct child of 
an arbitrary component.

Our current solution supports #1 via <composite:insertFacet>.  We 
support #3 at least to some degree via <composite:renderFacet>, though 
there are subtle differences in behavior between this an 
<composite:renderFacet>.  I believe that #2 is also somewhat covered, 
though fails in certain cases (such as passing a facet into a nested 
composite component).  These subtle differences are causing confusion 
about what should and shouldn't work, and I think are a general cause 
for concern with our current approach.

Ideally, we should support #1, #2 and #3 with a single tag, and we would 
use the same insertion strategy for all three operations.  So, we want 
an tag contract that is similar to ui:insert (single tag covers all 
cases), but actual insertion behavior is still open to debate.

This is getting somewhat repetitive I know (sorry), but I'll ask one 
more time...  Can anyone shed some light on why the multi-tag approach 
is preferable to the single tag approach - ie. is there a reason why we 
preferred not to follow the ui:insert model of having a single tag 
address all three of the above operations?  It is possible that there is 
a good reason, and if so, I would feel more comfortable with our current 
solution if I knew what that reason was. :-)

Regarding the appropriate implementation for inserting facets into the 
composite implementation (whether as facets or as direct children)...  
This is a tough call... I understand Ken's concerns about breaking the 
abstraction for composite component users, though with the introduction 
of composite:insertFacet it seems that we were willing to accept this 
behavior (or, perhaps, were unaware of the side effects).  One advantage 
that re-parenting has over referencing (symbolic link approach) is that 
re-parenting works with repeated component trees.  That is...

This works:

<composite:implementation>
  <ui:repeat>
    <h:panelGrid>
      <composite:insertFacet name="caption"/>
    </h:panelGrid>
  </ui:repeat>
</composite:implementation>


But this fails in subtle ways:

<composite:implementation>
  <ui:repeat>
    <h:panelGrid>
      <composite:renderFacet name="caption"/>
    </h:panelGrid>
  </ui:repeat>
</composite:implementation>


In particular, since the facet component does not end up as a child of 
the repeated component in the second case, the client ids will not be 
modified properly to reflect the current row.  If the facet happened to 
be an input component, we would be out of luck.

If I could make a single API change at this point, the one change that I 
would make would be to spec that <composite:insertFacet> determines the 
target facet name in the same way this is determined everywhere else - 
ie. by the presence of a wrapping <f:facet> tag.  This would allow us to 
address all three of the above cases with a single tag with consistent 
behavior, which in my mind would be a huge improvement.  (Presumably we 
could deprecate <composite:renderFacet> if we made this change.)

However, this is a big change.  It would mean that any existing cases 
that look like this:

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

Would need to be changed to this:

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

I am doubtful that we have the ability to make such a large change, but 
think it is at least worth considering.

If we cannot do this now, things that we should think about:

- Is there anything that we can do now that would limit the impact of 
the inconsistencies between our two composite facet tags?
- Is there anything that we can do now to better support cases like #2 
above (insert facet using different name)?  (This was the reason for my 
original email.)
- Where do we want to end up in 2.1?
- Is there anything that we can do now that will help us get to where we 
want to be in 2.1?



>   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).

Yep, I sense the implementation team cringing with every character that 
I type. ;-)


>
>>
>> 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.  It's been helpful working through these problems.

Andy





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