Hello Everyone,

I was wondering if it is possible to programmatically add a composite
component to a page just as you can a regular UI component.

For example:

Test3.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>

<html xmlns="http://www.w3.org/1999/xhtml";
    xmlns:ui="http://java.sun.com/jsf/facelets";
    xmlns:h="http://java.sun.com/jsf/html";
    xmlns:f="http://java.sun.com/jsf/core";
    xmlns:test="http://mycustomlib.com/mylib";>

<ui:composition template="/WEB-INF/templates/BasicTemplate.xhtml">
    <ui:define name="content">
        <h2>This test uses dynamic component to create composite
component</h2>
        <h:form>

                <test:dynamic/>
        </h:form>
    </ui:define>
</ui:composition>
</html>

mylib.taglib.xml:
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee";
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd";
        version="2.0">
        <namespace>http://mycustomlib.com/mylib</namespace>
        <composite-library-name>mylib</composite-library-name>

        <tag>
                <tag-name>dynamic</tag-name>
                <component>
                        <component-type>DynamicComponent</component-type>
                </component>
        </tag>

</facelet-taglib>

Important web.xml parameters set:

        <context-param>

                <param-name>javax.faces.FACELETS_LIBRARIES</param-name>

                <param-value>/WEB-INF/mylib.taglib.xml</param-value>

        </context-param>

        <context-param>


<param-name>org.apache.myfaces.STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME</param-name>

                <param-value>true</param-value>

        </context-param>


DynamicComponent.java:

@FacesComponent(value="DynamicComponent")
public class DynamicComponent extends UIPanel implements
SystemEventListener{
        public DynamicComponent(){
                UIViewRoot root = getFacesContext().getViewRoot();

                root.subscribeToViewEvent(PreRenderViewEvent.class, this);
        }

        protected FacesContext getFacesContext(){
                return FacesContext.getCurrentInstance();
        }

        @Override
        public boolean isListenerForSource(Object source) {
                return (source instanceof UIViewRoot);
        }

        @Override
        public void processEvent(SystemEvent event) {
                FacesContext context = getFacesContext();
                debug("in process event=" + event.getClass() + " src " +
event.getSource().getClass());

                if (!context.isPostback()){
                        debug("not a post back "  + this.getId());

                        //add a component
                        UIComponent c1 = createNewComponent
(UIInput.COMPONENT_TYPE);
                        debug("********** created UIInput *********");
                        /***************************************************
                         * Got a regular component, added that to tree and it
gets rendered
                         */
                        if (c1 != null){
                                debug(c1);
                                this.getChildren().add(c1);
                        }

                        //add composite component

                        UIComponent c2 = createNewComposite("mylib",
"MyCompositeComponent");
                        debug("********** created composite component
*********");
                        /***************************************************
                         * Got a composite component, added that to tree and it
doesn't get rendered
                         */
                        if (c2 != null){
                                debug(c2);
                                this.getChildren().add(c2);
                        }


                }else{
                        debug("not a post back");
                }

        }

        private UIComponent createNewComponent(String componentType) {
                return FacesContext.getCurrentInstance().getApplication
().createComponent(componentType);
        }

        private UIComponent createNewComposite(String lib, String component)
{

                Resource resource = FacesContext.getCurrentInstance
().getApplication().getResourceHandler().createResource(component +
".xhtml", lib);
                /***************************************************
                 * This is where problem is createComponent using resource
returns a component
                 * but it doesn;t get rendered when added to tree.
                 */
                return FacesContext.getCurrentInstance().getApplication
().createComponent(FacesContext.getCurrentInstance(), resource);
        }

        private void debug(UIComponent c){

                System.out.println(" component is null" + (c==null));
                System.out.println(" component id" + (c.getId()));
                System.out.println(" component family" + (c.getFamily()));
          System.out.println(" component tostring " + c.toString() );

        }

        private void debug(String s){
                System.out.println(s);
        }
}


MyCompositeComponent.xhtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>

<html xmlns="http://www.w3.org/1999/xhtml";
    xmlns:ui="http://java.sun.com/jsf/facelets";
    xmlns:cc="http://java.sun.com/jsf/composite";
    xmlns:h="http://java.sun.com/jsf/html";
    xmlns:f="http://java.sun.com/jsf/core";>
<cc:interface/>
<cc:implementation>
      <h:panelGrid columns="2">
                Name :  <h:inputText value=""></h:inputText>
                Password : <h:inputSecret value=""></h:inputSecret>
      </h:panelGrid>
      <h:commandButton value="Login" action="login"></h:commandButton>
</cc:implementation>
</html>

Basically what I'm trying to achieve here is the following:
Test3.xhtml uses the <dynamic/> tag defined in mylib.taglib.xml which
defines the component-type as DynamicComponent.  DynamicComponent.java in
turn
adds a stand alone UI component which renders correctly on the page and a
CompositeComponent (MyCompositeComponent.xhtml) which does not render on
the page.

When I run the above example on MyFaces 2.0.16 I see the following
exception in the logs:

HtmlComposite E   facet UIComponent.COMPOSITE_FACET_NAME not found when
rendering composite component j_id_8:j_id1

Is the above a valid use case?  I could not find anything specifically in
the JSF 2.0 Spec regarding programatically adding CompositeComponents
except for:
http://docs.oracle.com/javaee/6/api/javax/faces/application/Application.html#createComponent%28javax.faces.context.FacesContext,%20javax.faces.application.Resource%29

I've also tried doing the following in the same application with the same
result:

MyDynamicComponent.xml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>

<html xmlns="http://www.w3.org/1999/xhtml";
    xmlns:ui="http://java.sun.com/jsf/facelets";
    xmlns:cc="http://java.sun.com/jsf/composite";
    xmlns:h="http://java.sun.com/jsf/html";
    xmlns:f="http://java.sun.com/jsf/core";>
        <cc:interface componentType="DynamicComponent">
</cc:interface>

<cc:implementation>
</cc:implementation>
</html>

Test2.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>

<html xmlns="http://www.w3.org/1999/xhtml";
    xmlns:ui="http://java.sun.com/jsf/facelets";
    xmlns:h="http://java.sun.com/jsf/html";
    xmlns:f="http://java.sun.com/jsf/core";
    xmlns:test="http://java.sun.com/jsf/composite/mylib";>

<ui:composition template="/WEB-INF/templates/BasicTemplate.xhtml">
    <ui:define name="content">
        <h2>This test uses dynamic component to create composite
component</h2>
        <h:form>

                <test:MyDynamicComponent></test:MyDynamicComponent>
        </h:form>
    </ui:define>
</ui:composition>
</html>

With the following Warnings and the same exception as above:

HtmlRenderKit W   Unsupported component-family/renderer-type:
javax.faces.Panel/javax.faces.Composite

UIComponentBa W   No Renderer found for component {Component-Path : [Class:
javax.faces.component.UIViewRoot,ViewId: /Test2.xhtml][Class:
javax.faces.component.html.HtmlForm,Id: j_id_8][Class:
com.ibm.ws.jsf.fat.tests.DynamicComponent,Id: j_id_9]}
(component-family=javax.faces.Panel, renderer-type=javax.faces.Composite)
created from: /Test2.xhtml at line 15 and column 35


Any input would be very welcomed!

Thanks,

Paul Nicolucci

Reply via email to