As part of my work on JSR 314 (JSF 2.0) I've been reviewing the specification, Javadocs, and tag library docs for accuracy. One way I do this is to make examples that test drive what the documentation says JSF 2.0 will do.
To that end, here's Part 1 of my JSF 2.0 Test Drive... Developing a Facelet Composite Component
Composite Component Tag
<testcc:inputColor />
Description
An Ajaxified JSF 2.0 Facelet Composite Component that lets you choose an RGB color.
Downloadable Source Code
The Maven 2 project source code is licensed under the MPL 1.1 and is available at the edoras framework SVN repo:
Screen Shot
JSF 2.0 Terminology
In order to understand some of the terms used in the example, let's talk about some new JSF 2.0 Facelet terminology found in the documentation:
| Composite Component: | Refers to an XHTML file that contains a piece of reusable markup that is encapsulated by the ui:component tag |
| Composite Component Author: | Refers to the person that develops the composite component |
| Composite Component Tag: | Refers to a tag like <testcc:inputColor /> that lets folks create instances of the composite component |
| Using Page: | Refers to the Facelet XHTML f:view that contains the composite component tag |
| Page Author: | Refers to the person that that creates an instance of the composite component on a using page. |
Composite Component Source: inputColor.xhtml
Here's the markup for the component itself. Note how JSF 2.0 now has a nice ui:interface section for defining the usage contract for the page author to abide by, and a ui:implementation section for hiding the inner workings of the component itself (the reusable markup). Also note that I didn't have to write any Javascript to perform Ajax updates in the DOM -- JSF 2.0 has that built-in with the f:ajax tag. The render attribute of f:ajax specifies a space-delimited list of "ids" that are to be re-rendered after the form is submitted via XmlHttpRequest().
<ui:component xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/1999/xhtml http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
<cc:interface>
<cc:attribute name="value" required="true" type="org.edorasframework.example.Color">
<cc:attribute name="red" required="true" />
<cc:attribute name="green" required="true" />
<cc:attribute name="blue" required="true" />
</cc:attribute>
<cc:actionSource name="colorPalette" targets="redSelector greenSelector blueSelector" />
<cc:editableValueHolder name="colorFields" targets="redInputText greenInputText blueInputText" />
<cc:facet name="header" required="true" />
</cc:interface>
<cc:implementation>
<cc:renderFacet name="header" />
<f:ajax render="preview kids">
<h:panelGrid columns="2">
<h:outputLabel value="R:" />
<h:inputText id="redInputText" value="#{cc.attrs.value.red}">
<f:validateLongRange minimum="0" maximum="255" />
</h:inputText>
<h:outputLabel value="G:" />
<h:inputText id="greenInputText" value="#{cc.attrs.value.green}">
<f:validateLongRange minimum="0" maximum="255" />
</h:inputText>
<h:outputLabel value="B:" />
<h:inputText id="blueInputText" value="#{cc.attrs.value.blue}">
<f:validateLongRange minimum="0" maximum="255" />
</h:inputText>
</h:panelGrid>
</f:ajax>
<h:outputText value="Color Preview: " />
<c:set value="#{cc.attrs.value.red}" var="red" />
<c:set value="#{cc.attrs.value.green}" var="green" />
<c:set value="#{cc.attrs.value.blue}" var="blue" />
<c:set value="#{red},#{green},#{blue}" var="rgb" />
<h:outputText id="preview" value=" " style="border: 1px solid; padding: 1px 10px; background-color: rgb(#{rgb});" />
<f:ajax render="redInputText greenInputText blueInputText preview kids">
<h:panelGrid border="1" columns="3">
<f:facet name="header">
<h:outputText value="Color Palette" />
</f:facet>
<h:commandLink id="redSelector" value="Red">
<f:setPropertyActionListener target="#{cc.attrs.value.red}" value="255" />
<f:setPropertyActionListener target="#{cc.attrs.value.green}" value="0" />
<f:setPropertyActionListener target="#{cc.attrs.value.blue}" value="0" />
</h:commandLink>
<h:commandLink id="greenSelector" value="Green">
<f:setPropertyActionListener target="#{cc.attrs.value.red}" value="0" />
<f:setPropertyActionListener target="#{cc.attrs.value.green}" value="255" />
<f:setPropertyActionListener target="#{cc.attrs.value.blue}" value="0" />
</h:commandLink>
<h:commandLink id="blueSelector" value="Blue">
<f:setPropertyActionListener target="#{cc.attrs.value.red}" value="0" />
<f:setPropertyActionListener target="#{cc.attrs.value.green}" value="0" />
<f:setPropertyActionListener target="#{cc.attrs.value.blue}" value="255" />
</h:commandLink>
</h:panelGrid>
</f:ajax>
<br />
<h:panelGroup id="kids">
<cc:insertChildren />
</h:panelGroup>
</cc:implementation>
</ui:component>
Using Page Source: usingPage.xhtml
Here's what the using page looks like, and how it creates an instance of the composite component by using a composite component tag. Note that with JSF 2.0, you can attach action-listeners and value-change-listeners to composite components. Additionally, you can specify children inside the composite component tag, provided that the composite component author uses the ui:insertChildren tag to place the children somewhere in the reusable markup. The testcc:inputColor tag shown below inserts an h:panelGrid as a child, which shows the "You Selected..." part to the user.
<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:testcc="http://java.sun.com/jsf/composite/testcc"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/1999/xhtml http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
<h:head>
<title>Using Page</title>
</h:head>
<h:body>
<h:form>
<h:messages />
<testcc:inputColor value="#{modelManagedBean.color}">
<f:facet name="header">
<h:outputText value="Please choose a color" />
</f:facet>
<f:actionListener for="colorPalette" type="org.edorasframework.example.ColorActionListener" />
<f:valueChangeListener for="colorFields" type="org.edorasframework.example.ColorValueChangeListener" />
<!--
The following h:panelGrid will be used by the cc:insertChildren tag in the
cc:implementation section of the testcc:inputColor composite component.
-->
<h:panelGrid columns="2">
<f:facet name="header">
<h:outputText value="You Selected: " />
</f:facet>
<h:outputLabel value="Red:" />
<h:outputText value="#{modelManagedBean.color.red}" />
<h:outputLabel value="Green:" />
<h:outputText value="#{modelManagedBean.color.green}" />
<h:outputLabel value="Blue:" />
<h:outputText value="#{modelManagedBean.color.blue}" />
</h:panelGrid>
</testcc:inputColor>
<br />
<h:commandButton value="Submit" />
</h:form>
</h:body>
</f:view>
Composite Component Value POJO: Color.java
Here is the POJO that is used to supply a value to the composite component:
package org.edorasframework.example;
import java.io.Serializable;
/**
* This class provides a way of representing a color as an RGB triplet.
*
* @author "Neil Griffin"
*/
public class Color implements Serializable {
private static final long serialVersionUID = -3810147232196826614L;
private int red;
private int green;
private int blue;
public int getBlue() {
return blue;
}
public int getGreen() {
return green;
}
public int getRed() {
return red;
}
public void setBlue(int blue) {
this.blue = blue;
}
public void setGreen(int green) {
this.green = green;
}
public void setRed(int red) {
this.red = red;
}
}
The remainer of the files (action listener, value change listener, model managed bean) are all available from the SVN repos.
Anyways, hope you enjoyed seeing JSF 2.0 in action! Good stuff ahead!

