webtier@glassfish.java.net

Re: Programmatic or dynamic construction of composite components

From: <webtier_at_javadesktop.org>
Date: Sun, 28 Feb 2010 13:14:02 PST

Assume we have a fairly simple composite component:
[pre]
<html
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:composite="http://java.sun.com/jsf/composite">
    
  <!-- INTERFACE -->
        <composite:interface>
                <composite:facet name="foo"/>
                <composite:attribute name="value"/>
        </composite:interface>

  <!-- IMPLEMENTATION -->
    <composite:implementation>
                <h:inputText id="value" value="#{cc.attrs.value}"/>
                [<composite:renderFacet name="foo"/>]
                (<composite:insertChildren/>)
        </composite:implementation>
</html>
[/pre]

Using it from the Facelets page is straightforward:
[pre]
<d:test id="tag" value="#{stringValue.value}">
        <f:facet name="foo">
                <h:outputText value="Foo"/>
        </f:facet>
        <h:outputText value="Bar"/>
</d:test>
[/pre]

I'd like to create this composite component programmatically - ad I'd like to set the [b]value[/b] as well as the [b]facet foo[/b] and [b]children components[/b] programmatically as well.

Here's the first thing I tried:

[pre]
public void setComponent1(UIComponent component) throws Exception {

                Application application = facesContext.getApplication();
                Resource resource = application.getResourceHandler().createResource(
                                "test.xhtml", "components/dynamicfaces");

                UIComponent compositeComponent = application.createComponent(
                                facesContext, resource);
                component.getChildren().add(compositeComponent);

                ValueExpression value = application.getExpressionFactory()
                                .createValueExpression(facesContext.getELContext(),
                                                "#{stringValue.value}", String.class);

                compositeComponent.setValueExpression("value", value);

                UIOutput foo = (UIOutput) application
                                .createComponent(HtmlOutputText.COMPONENT_TYPE);

                foo.setValue("Foo");
                compositeComponent.getFacets().put("foo", foo);

                UIOutput bar = (UIOutput) application
                                .createComponent(HtmlOutputText.COMPONENT_TYPE);
                bar.setValue("Bar");
                compositeComponent.getChildren().add(bar);

                this.component = component;
        }
[/pre]

This is the most straightforward thing, this is what I expect to work and this is what I think is designed in the specification. It's also what Ed Burns mentions here:

http://forums.java.net/jive/thread.jspa?messageID=339830

Very naive.

It fails with an exception with the following cause:

Unable to find composite component root for composite component with id null and class javax.faces.component.UINamingContainer

To avoid the exception I've added:

[pre]
UIComponent compositeRoot = application
                                .createComponent(UIPanel.COMPONENT_TYPE);
                compositeRoot.setRendererType("javax.faces.Group");

                compositeComponent.getFacets().put(UIComponent.COMPOSITE_FACET_NAME,
                                compositeRoot);
[/pre]

The exception was gone, but the component was still empty.
[Message sent by forum member 'lexi' (valikov_at_gmx.net)]

http://forums.java.net/jive/thread.jspa?messageID=389243