NetBeans IDE provide comprehensive feature set to build applications using Java Server Faces 2 (JSR 314). This Tip Of The Day (TOTD) explains how to create JSF composite components using wizards provided by the NetBeans IDE.
The JSF2 specification, section 3.6 defines composite components as:
A tree of "UIComponent" instances, rooted at a top level component, that can be thought of and used as a single component in a view. The component hierarchy of this subtree is described in the composite component defining page.
This definition is good from the specification perspective but can help with some layman explanation. Essentially, a composite component is what it says – a composition of two or more components such that it behaves like a single component. For example, consider four components in a panel grid where 2 components are "h:outputText" to display prompts and other 2 are "h:inputText" to receive input from the user. The composite components allow all of these components (1 panel grid + 2 "h:inputText" + 2 "h:outputText") packaged as a single component.
Resource Handling and Facelets, both features newly introduced in the JSF2 specification, makes the creation of composite component much easier. The Resource Handling defines a standard location for bundling resources in a web application and Facelets defines a cleaner templating language that enables composition. In technical terms:
A composite component is any Facelet markup file that resides inside of a resource library.
Lets create a simple Web application using JSF 2 that accepts a username/password and displays it in a new page. The application is first created using the traditional "h:inputText" and "h:outputText" elements and is then converted to use a composite component.
Before we dig into composite component creation using JSF2, here are the steps listed to create one using JSF 1.2:
- Implement UIComponent subclass
- Markup rendering code in Renderer
- Register your component and renderer in faces-config.xml
- Implement your JSP tag
- And the TLD
There is Java code involved, sub-classing from JSF classes, deployment descriptor editing in "faces-config.xml", declaring TLDs and then implementing the JSP tag. Creating a composite component in JSF 1.2 was quite a chore and spread all over. There are lots of files
With that background, lets see what it takes us to create a composite component using JSF2.
The CDI backing bean for the application looks like:
package server;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named("simplebean")
@RequestScoped
public class SimpleBean {
String name;
String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The "index.xhtml" Facelet markup file looks like:
<?xml version='1.0' encoding='UTF-8' ?>
<!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">
<h:head>
<title>Enter Name & Password</title>
</h:head>
<h:body>
<h1>Enter Name & Password</h1>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Name:"/>
<h:inputText value="#{simplebean.name}" title="name"
id="name" required="true"/>
<h:outputText value="Password:"/>
<h:inputText value="#{simplebean.password}" title="password"
id="password" required="true"/>
</h:panelGrid>
<h:commandButton action="show" value="submit"/>
</h:form>
</h:body>
</html>
And the "show.xhtml" Facelet markup looks like:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html">
<h:head>
<title>Show Name & Password</title>
</h:head>
<h:body>
<h1>Show Name & Password</h1>
<h:panelGrid columns="2">
<h:outputText value="Name:"/>
<h:outputText value="#{simplebean.name}" />
<h:outputText value="Password:"/>
<h:outputText value="#{simplebean.password}" />
</h:panelGrid>
</h:body>
</html>
Now select the <panelGrid> fragment in "index.xhtml" as shown below:
Right-click and select "Convert To Composite Component …" and specify the values as given in the wizard below:
Note, most of the values are default and only the "File Name:" is changed. After clicking on "Finish" in the wizard, the updated page looks like:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:ez="http://java.sun.com/jsf/composite/ezcomp">
<h:head>
<title>Enter Name & Password</title>
</h:head>
<h:body>
<h1>Enter Name & Password</h1>
<h:form>
<ez:username-password/>
<h:commandButton action="show" value="submit"/>
</h:form>
</h:body>
</html>
The namspace/prefix "http://java.sun.com/jsf/composite/ezcomp" is added to the markup page. <ez:username-password> is the composite component used instead of those multiple components. The namespace prefix, "ez", and the tag name, "username-password", are chosen based upon the values entered in the wizard.
The JSF 2 specification, section 3.6.1.4 defines that:
The occurrence of the string “http://java.sun.com/jsf/composite/” in a Facelet XML namespace declaration means that whatever follows that last “/” is taken to be the name of a resource library.
The resource library location is relative to the Facelet markup file that is using it. So in our case, all the code is rightly encapsulated in the "resources/ezcomp/username-password.xhtml" file as:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html">
<!-- INTERFACE -->
<cc:interface>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<h:panelGrid columns="2">
<h:outputText value="Name:"/>
<h:inputText value="#{simplebean.name}" title="name"
id="name" required="true"/>
<h:outputText value="Password:"/>
<h:inputText value="#{simplebean.password}" title="password"
id="password" required="true"/>
</h:panelGrid>
</cc:implementation>
</html>
Notice, the composite component name matches the Facelet markup file name. The markup file lives in "resources/ezcomp" directory as indicated by the namespace value.
<cc:interface> defines metadata that describe the characteristics of component, such as supported attributes, facets, and attach points for event listeners. <cc:implementation> contains the markup substituted for the composite component.
The "index.xhtml" page is using the composite component and is conveniently called the using page. Similarly the "username-password.xhtml" page is defining the composite component and is conveniently called the defining page. In short, creating composite components in JSF2 requires the following steps:
- Move the required tags to a separate Facelet markup file, "defining page", in the "resources" directory
- Declare the namespace/prefix derived from "http://java.sun.com/jsf/composite" and the directory name
- Refer the composite component in the "using page".
Much simpler and cleaner than JSF 1.2. Are you using JSF 2 composite components ?
The entire source code used in this blog can be downloaded here.
JSF 2 implementation is bundled with GlassFish Server Open Source Edition, try it today!
Technorati: totd glassfish v3 netbeans jsf2 javaee composite components ajax