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

[jsr344-experts] Re: [jsr-344-experts] should really a composite component requires NamingContainer interface?

From: Leonardo Uribe <lu4242_at_gmail.com>
Date: Fri, 1 Jul 2011 18:11:49 -0500

Hi

BS > Isn't what you are complaining about really a failure abstraction in JSF's
BS > handling of composite components?

In my understanding, the idea with the introdution of composite
components was create a clean interface to replace facelets user tags,
with typed properties and many other features to make easier write
components.

Unfortunately, there are some cases where you want to replace some
facelets code with a composite component, but you can't because the
composite component base class is a NamingContainer. Previously, I
described the most typical use case and prove that it is possible to
get rid of that restriction. My position about this topic is since
there is nothing that enforce that, it is possible to assume the
opposite and at least do it in MyFaces Core.

It can be considered a failure abstraction, but the fact is that there
is no restriction to implement it, so I'm considering it an
implementation failure.

BS > Shouldn't we be fixing findComponent to
BS > work correctly instead of adding a workaround that only works if no ids are
BS > set on the contents of the composite component?

I don't believe a fix on findComponent could do the trick, because
clientId structure is used for invokeOnComponent and visitTree
algorithm, so any change there will break partial state saving
algorithm.

It is evident that by default a composite component should be a
NamingContainer, but allow any component to be a composite component
base does not harm, as long as the developer respect the rule of no
ids set inside composite component content.

I still have to do some tests to know how far can we go in that direction.

Leonardo Uribe

>
> -- Blake Sullivan
>
> On 6/28/11 6:15 PM, Leonardo Uribe wrote:
>>
>> Hi
>>
>> In theory, a "non explicit" requeriment for a composite component
>> class is it should implement NamingContainer interface. Note I said
>> "non explicit", because in practice there is nothing on the spec that
>> enforces that. The only mention can be found on facelets taglib doc
>> for composite:interface, section titled Naming containers within
>> composite components:
>>
>> "... Composite components are themselves naming containers so that any
>> possible id conflicts between inner components and components in the
>> using page are avoided. However, special care must be taken when using
>> naming containers in the<composite:implementation>  section. ..."
>>
>> It is true that by default, composite component base class is
>> UINamingContainer, and the component family should be
>> "javax.faces.NamingContainer" to get the renderer class.
>>
>> Let's take a look at this simple example:
>>
>> <h:form id="frmTst">
>>         <ui:include src="demoui1.xhtml"/>
>>         <ui:include src="demoui1.xhtml"/>
>>         <ui:include src="demoui1.xhtml"/>
>> </h:form>
>>
>> demoui1.xhtml
>>
>> <ui:composition>
>>     <p><h:commandButton value="Hello World!"/></p>
>> </ui:composition>
>>
>> The previous code works in both MyFaces and Mojarra. This is valid
>> from facelets 1.1.x. The idea is as long as there is no component with
>> "id" set, the previous code will work. Combinations of c:if and
>> ui:include could be possible, but this work well only on MyFaces 2.0.x
>> and upper and facelets 1.1.x. In Mojarra 2.0.x some changes were done
>> that makes such cases not work correctly (but in my opinion c:if is
>> something evil, because it causes a lot of nightmares).
>>
>> Now let's try to convert the previous case into a composite component,
>> but this time let's create a normal component that does not implement
>> NamingContainer, because after all the previous snippet followed the
>> rule that no components with id set were added:
>>
>> <h:form id="frmTst">
>>        <test:ccc value="Hello World!"></test:ccc>
>>         <test:ccc value="Hello World!"></test:ccc>
>>         <test:ccc value="Hello World!"></test:ccc>
>> </h:form>
>>
>> ccc.xhtml
>>
>> <cc:interface componentType="test.ComponentCCC">
>>        <cc:attribute name="value" type="java.lang.String" />
>> </cc:interface>
>> <cc:implementation>
>>     <p><h:commandButton value="#{cc.attrs.value}"/></p>
>> </cc:implementation>
>>
>> @FacesComponent("test.ComponentCCC")
>> public class ComponentCCC extends UIOutput
>> {
>>     public final static String COMPONENT_TYPE = "test.ComponentCCC";
>>
>>
>>     @Override
>>     public String getFamily()
>>     {
>>         return UINamingContainer.COMPONENT_FAMILY;
>>     }
>> }
>>
>> In theory, since all ids are generated, everything should work like in
>> ui:include case. In practice, the previous code works on MyFaces but
>> does not on Mojarra.
>>
>> Why somebody could want to do this trick? Because NamingContainer has
>> its effects, specially with UIComponent.findComponent. Suppose you
>> want to create a component that works as a panel. You can imagine
>> something like this:
>>
>> <h:form prependId="true">
>>     <y:myPanel>
>>         <h:inputText id="field1" ... />
>>         <!-- more components -->
>>     </y:myPanel>
>> </h:form>
>>
>> y.xhtml
>>
>> <cc:implementation>
>>     <!-- some javascript markup with html and css -->
>>     <cc:insertChildren />
>>     <!-- some javascript markup with html and css -->
>> <cc:implementation>
>>
>> The user wants that the final clientId be "field1", but instead he/she
>> has "[generated id]:field1", and the worst part is if you need some
>> call to invokeOnComponent or findComponent, you have to set the id of
>> your composite component and take into account the internals of such
>> cc to get the component instance.
>>
>> Basically the only thing we need to do on Mojarra to make it work is
>> do some small changes on id generation. Note in this case, the xhtml
>> file related to the composite component will only be used to render
>> the markup, and other stuff like attached objects should be done like
>> with normal components: adding the code on the class.
>>
>> Allow this behavior could be great, because makes possible to write
>> more JSF typical components as composite components, keeping the
>> markup on a xhtml file and the logic on the component/renderer
>> classes.
>>
>> Note that the trick proposed here is compliant with the spec, just
>> like the one proposed long time ago related to customize the renderer
>> instance for a composite component. In fact, I'm looking for a way to
>> write components more easily, and do this trick for me seems the way
>> to go.
>>
>> Should Mojarra fix this issue and enforce better compatibility with
>> facelets 1.1.x? Any comments about this one? Suggestions are welcome
>>
>> regards,
>>
>> Leonardo Uribe
>
>