Creating Composition Components in JSF 2.0

Exclusive offer: get 50% off this eBook here
JSF 2.0 Cookbook

JSF 2.0 Cookbook — Save 50%

Over 100 simple but incredibly effective recipes for taking control of your JSF applications

$26.99    $13.50
by Anghel Leonard | June 2010 | Java Open Source Web Development

In this article by Anghel Leonard, author of the book JSF 2.0 Cookbook, we will cover the following:

  • Creating composition components in JSF 2.0
  • Passing sub-elements to composition components
  • Passing actions to composition components

(For more resources on JSF, see here.)

A great feature of Facelets consists in composition components (available starting with JSF 2.0). For a better understanding, we will start with a traditional application, and we will compare it with an application that uses composition components. At the end, you will love composition components.

Getting ready

We have developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.

How to do it...

Let's suppose that we have a list of books, characterized by title, author, and price, and we need to display this list in a table and provide the sorting (ascending/descending) action for each category (see next screenshot):

Creating Composition Components in JSF 2.0

Focusing on this view (not on functionality or backing beans), we will probably write a JSF page like the following (this is the traditional approach):

<!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"
xmlns:f="http://java.sun.com/jsf/core">

<h:head>
<title> Composition components in JSF 2.0</title>
<style type="text/css">
.header { text-align: left;
letter-spacing:5px;
color:#000099
}
.odd { background-color: yellow }
.even { background-color: orange }
</style>
</h:head>

<f:view>
<h:form>
<h:dataTable id="booksId" value="#{booksStore.books}" var="bk"
rowClasses="odd, even" headerClass="header">

<!-- book title -->
<h:column>
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Book Title" />
<f:verbatim>[</f:verbatim>
<!-- Ascending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="booktitleascid" value="ascending" />
<f:param name="by" value="title"/>
<f:param name="order" value="ascending"/>
</h:commandLink>

<h:outputText value="," />
<!-- Descending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="booktitledescid" value="descending" />
<f:param name="by" value="title"/>
<f:param name="order" value="descending"/>
</h:commandLink>
<f:verbatim>]</f:verbatim>

</h:panelGroup>
</f:facet>

<h:outputText value="#{bk.title}" />
</h:column>

<!-- book author -->
<h:column>
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Book Author" />
<f:verbatim>[</f:verbatim>
<!-- Ascending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="bookauthorascid" value="ascending" />
<f:param name="by" value="author"/>
<f:param name="order" value="ascending"/>
</h:commandLink>

<h:outputText value="," />
<!-- Descending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="bookauthordescid" value="descending" />
<f:param name="by" value="author"/>
<f:param name="order" value="descending"/>
</h:commandLink>

<f:verbatim>]</f:verbatim>
</h:panelGroup>
</f:facet>
<h:outputText value="#{bk.author}" />

</h:column>

<!-- book price -->
<h:column>
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Book Price" />

<f:verbatim>[</f:verbatim>
<!-- Ascending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="bookpriceascid" value="ascending" />
<f:param name="by" value="price"/>
<f:param name="order" value="ascending"/>
</h:commandLink>

<h:outputText value="," />
<!-- Descending link -->
<h:commandLink action="#{booksStore.sortBooks}">
<h:outputText id="bookpricedescid" value="descending" />
<f:param name="by" value="price"/>
<f:param name="order" value="descending"/>
</h:commandLink>
<f:verbatim>]</f:verbatim>
</h:panelGroup>
</f:facet>
<h:outputText value="#{bk.price}" />

</h:column>
</h:dataTable>

</h:form>
</f:view>
</html>

In addition, we have two backing beans as follows:

A Book.java backing bean that maps the book characteristics:

package bean;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class Book {

private String title;
private String author;
private String price;

public Book(String title, String author, String price) {
this.title = title;
this.author = author;
this.price = price;
}

public Book() {
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public String getPrice() {
return price;
}

public void setPrice(String price) {
this.price = price;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}

A BooksStore.java backing bean that defines a list of Book instances and defines a method for sorting the books by title, author, or price is shown next:

package bean;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

@ManagedBean
@SessionScoped
public class BooksStore {

private List books = new ArrayList();

public BooksStore() {
books.add(new Book("Learning Website Development with Django",
"Ayman Hourieh", "€26.34"));
books.add(new Book("Building Websites with Joomla! 1.5",
"Hagen Graf", "€29.74"));
books.add(new Book("ASP.NET 3.5 Application Architecture and
Design", "Vivek Thakur", "€30.99"));
books.add(new Book("Drupal 6 Themes", "Ric Shreves", "€26.34"));
books.add(new Book("WordPress Theme Design",
"Tessa Blakeley Silver", "€26.34"));
}

public List getBooks() {
return books;
}

public void setBooks(List books) {
this.books = books;
}

public void sortBooks() {
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletRequest httpServletRequest = (HttpServletRequest)
facesContext.getExternalContext().getRequest();

String by = httpServletRequest.getParameter("by");
String order = httpServletRequest.getParameter("order");

System.out.println("The books should be order " + order +
" by " + by + "!");

//ordering books
}
}

Obviously, the redundancy of the JSF view is annoying and very primitive. We can fix this by defining a composition component that can be invoked instead of repeating code (the backing beans remain unchanged). The composition component can be created by following a few steps. To start with, we define the composition component page and place it under the /WEB-INF folder:

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

<ui:composition>
<h:column>
<f:facet name="header">
<h:panelGroup>
<f:verbatim>Book-</f:verbatim>
<h:outputText value="${attr}" />
<f:verbatim>[</f:verbatim>

<!-- Ascending link -->
<h:commandLink action="#{compbean.sortBooks}">
<h:outputText value="ascending" />
<f:param name="by" value="${attr}"/>
<f:param name="order" value="ascending"/>
</h:commandLink>

<h:outputText value="," />

<!-- Descending link -->
<h:commandLink action="#{compbean.sortBooks}">
<h:outputText value="descending" />
<f:param name="by" value="${attr}"/>
<f:param name="order" value="descending"/>
</h:commandLink>

<f:verbatim>]</f:verbatim>
</h:panelGroup>
</f:facet>
<h:outputText value="${book[attr]}" />

</h:column>
</ui:composition>
</html>

Next, we define a tag library file to map the tag name to the tag source or, in other words, to map the name of the composition component with the composition component source page. In addition, it defines the namespace used to access the tag. This is an XML file that looks like this:

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://www.my.facelets.component.com/jsf</namespace>

<tag>
<tag-name>tableColumn</tag-name>
<source>mycomp.xhtml</source>
</tag>

</facelet-taglib>

JSF 2.0 Cookbook Over 100 simple but incredibly effective recipes for taking control of your JSF applications
Published: June 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

(For more resources on JSF, see here.)

Further, we declare the tag library in the web.xml descriptor—you need to indicate the path to the tag library as follows:

<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/tags/taglibmycomp.xml</param-value>
</context-param>

Finally, we import the corresponding namespace and invoke the composition component. The client page for our composition component is listed as follows:

<!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"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:x="http://www.my.facelets.component.com/jsf">

<h:head>
<title>Composition components in JSF 2.0</title>
<style type="text/css">
.header { text-align: left;
letter-spacing:5px;
color:#000099
}
.odd { background-color: yellow }
.even { background-color: orange }
</style>
</h:head>

<f:view>
<h:form>
<h:dataTable id="booksId" value="#{booksStore.books}" var="bk"
rowClasses="odd, even" headerClass="header">

<x:tableColumn book="${bk}" attr="title"
compbean="${booksStore}" />
<x:tableColumn book="${bk}" attr="author"
compbean="${booksStore}" />
<x:tableColumn book="${bk}" attr="price"
compbean="${booksStore}" />
</h:dataTable>

</h:form>
</f:view>
</html>

As you can see, now the code is simpler, cleaner, and more optimal.

Regarding the values passed by the client page to the composition component, we need to notice the following (is very important to keep this in mind and to adapt it to your applications):

  • When the composition component is invoked we pass three attributes, representing a Book instance (bk), a constant string, and a BooksStore instance (booksStore)
  • The Book is passed using the book="${bk}" construction, and it is used as the ${book[attr]} construction, where attr can be title, author, or price depending on attr attribute value
  • The constant is passed as attr="title", "author", and "price" and it is used as ${attr}
  • The BooksStore instance is passed as compbean="${booksStore}", and it is used as #{compbean.sortBooks}

How it works...

The composition component acts as a reusable component. The client page calls the composition component as many times as it wants and each time it customizes it by passing it different values. As you just saw, Facelets provides support for passing different kinds of values, and, as you will see in the next two recipes, we can go even deeper on this line. As we can customize the composition component aspect, behavior, and so on, we can create a application without multiplying "islands" of code all over the application. Put this in correlation with templating and you will obtain great code!

Passing sub-elements to composition components

First of all, you need to keep in mind that this recipe uses the knowledge and code from the previous recipe, therefore it is recommended to read the previous recipe first!

Now, focusing on this recipe, you should know that the key to its design lies in the fact that a Facelets composition component is actually a type of template. Based on this important observation, we can pass a template argument using the ui:define (associated to a corresponding ui:insert). Also, we can pass the body as a default ui:insert.

Getting ready

We have developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.

How to do it...

First, we place an anonymous ui:insert in the composition component (you should place it exactly in the place where you need it to be replaced by Facelets) For example, we place it in each table column as shown next:

...
<h:outputText value="${book[attr]}" />

<ui:insert />
</h:column>

</ui:composition>
</html>

Now, when we invoke the composition component, the anonymous insert introduces the passed body. If the body is present, then nothing is introduced. In the following example, we are using a body for author and price columns (our body is just an f:verbatim component, but it can be anything else).

...
<x:tableColumn book="${bk}" attr="title" compbean="${booksStore}" />
<x:tableColumn book="${bk}" attr="author" compbean="${booksStore}">
<f:verbatim> [*****]</f:verbatim>
</x:tableColumn>
<x:tableColumn book="${bk}" attr="price" compbean="${booksStore}">
<f:verbatim> - Promotion!</f:verbatim>
</x:tableColumn>
...

Now the rendered table looks similar to the following screenshot:

Creating Composition Components in JSF 2.0

How it works...

Well, as we said in the description of the recipe, the secret lies in the fact that a Facelets composition component is acting like a template. I think that this observation says it all!

Passing actions to composition components

In the recipe Creating composition components in JSF 2.0, we passed different types of values to our composition component. In this recipe, we take a step forward and pass an action to it, instead of explicitly mapping the action in the composition component.

Getting ready

We have developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.

How to do it...

The solution is based on two steps:

  1. We pass the action name as shown next (focus on the action attribute):

    ...
    <x:tableColumn book="${bk}" attr="title" action="sortBooks"
    compbean="${booksStore}" />
    ...

  2. We use the passed action in the composition component:

    ...
    <h:commandLink action="#{compbean[action]}">
    <h:outputText value="ascending" />
    <f:param name="by" value="${attr}"/>
    <f:param name="order" value="ascending"/>
    </h:commandLink>
    ...

That's all! Now you should be able to pass an action binding to create different elements such as toolbars.

How it works...

As the standard EL can't help us here, we have used a little trick supported by Facelets—we have referenced the value binding in a generic way!

Summary

In this article, we saw how to work with composition components, and how to pass actions, and sub-elements to composition components.


Further resources on this subject:

JSF 2.0 Cookbook Over 100 simple but incredibly effective recipes for taking control of your JSF applications
Published: June 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Anghel Leonard

Anghel Leonard is a senior Java developer with more than 13 years of experience in Java SE, Java EE, and related frameworks. He has written and published more than 50 articles about Java technologies and more than 500 tips and tricks for many websites that are dedicated to programming. In addition, he has written the following books:

  • Tehnologii XML XML în Java, Albastra
  • Jboss Tools 3 Developer's Guide, Packt Publishing
  • JSF 2.0 Cookbook, Packt Publishing
  • JSF 2.0 Cookbook: LITE, Packt Publishing
  • Pro Java 7 NIO.2, Apress
  • Pro Hibernate and MongoDB, Apress

Currently, Anghel is developing web applications using the latest Java technologies on the market (EJB 3.0, CDI, Spring, JSF, Struts, Hibernate, and so on). Over the past two years, he's focused on developing rich Internet applications for geographic information systems.

Books From Packt

Amazon SimpleDB Developer Guide
Amazon SimpleDB Developer Guide

GlassFish Security
GlassFish Security

Oracle JRockit: The Definitive Guide
Oracle JRockit: The Definitive Guide

Plone 3 Multimedia
Plone 3 Multimedia

Moodle 1.9 for Design and Technology
Moodle 1.9 for Design and Technology

Spring Python 1.1
Spring Python 1.1

Oracle Application Express 3.2 – The Essentials and   More
Oracle Application Express 3.2 – The Essentials and More

Apache MyFaces 1.2 Web Application   Development
Apache MyFaces 1.2 Web Application Development

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software