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

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

From: Blake Sullivan <blake.sullivan_at_oracle.com>
Date: Fri, 01 Jul 2011 15:23:40 -0700

Leonardo,

Isn't what you are complaining about really a failure abstraction in
JSF's handling of composite components? Shouldn't we be fixing
findComponent to work correctly instead of adding a workaround that only
works if no ids are set on the contents of the composite component?

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