Sunday, October 17, 2010

JSF 2.0 - New features (part 1 of 3)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28 and MyFaces 2.1.7. 

Requirements:
  • working "Hello World" example in JSF 2.0 as a basis (from here)
You will learn:
  • templating with Facelets
  • simplified page navigation
In the previous post I showed how to create classic "Hello World" application in JSF 2.0. The example was created in the simplest possible way. I focused on generating and setting up working and ready to use project in Eclipse. Created application did not differ much from similar "Hello World" applications in JSF 1.2, because I did not use JSF 2.0 built-in featues. Now it is a time to show what new features are in JSF 2.0 and how they can improve development web applications. 

Sample application:
In order to go higher than "Hello World" level we will create fully functional mini application which will serve as an example for mentioned JSF 2.0 features.
Let's assume that we are creating a web application for bicycle shop. Our application should present a list of available bikes. Bikes will be divided because of their type like MTB, Trekking and Cross bikes. In addition bike list will have a filter allowing to display only bikes with a special discount price. User should be able to display detailed information about selected bike from the presented list. We will use those pages in application:
  • bikesShop.xhtml - start page presenting information about bike shop
  • bikesList.xhtml - page presenting bikes of given type
  • bikeDetails.xhtml - page presenting detailed information about bike displayed on bikesList.xhtml
Under the hood we will use those classes:
  • BikeDataProvider.java - singleton, acts as service which belongs to business logic. Responsible for loading bikes of certain type and loading single bike with its details. For simplicity all bikes instances are created and stored inside that class.
  • Bike.java - a class from the model representing single bike instance. A list of bike instances is created and used inside BikeDataProvider.java.
  • BikeDetails.java, BikesList.java - managed beans used for bikeDetails.xhtml and bikesList.xhtml respectively. They call BikeDataProvider.java for loading bikes list or single bike.

Web application will have popular and standard layout - header on top, menu on left, content on righ, footer on bottom. Header will have shop's logo and name, menu will have bike types listed, content will have some information about the shop and will display bikes list for given type, footer will be empty with some background color. The whole application will look like this:

bikesShop.xhtml:


bikesList.xhtml:


bikesDetails.xhtml:


Facelets - templating.
One of the key feature of Facelets is ability to create page templates. Have a look at our sample applications screenshot above - all of them have common content like header, left menu and footer. If we had JSF application based on JSP pages without using Facelets, those elements would be included separately into source code of each web page. Imagine small change in the header - it may become a maintenance nightmare because we have to change source code of all pages where header is visible. With the Facelets is it possible to extract common content and put it into one page template. The template has special sections where variable content will be displayed - pages which use the template "injects" to those sections their specific content.

For our application we will create a template page named shopTemplate.xhtml which will act as a template for three pages visible above (bikesShop.xhtml, bikesList.xhtml, bikeDetails.xhtml). The whole page layout common for all pages will be defined inside the single template page. This gives us another advantage - we can follow one of the best practises in designing web pages here - separate the structure from the presentation. The template will contain only the pages structure while the whole presentation will be placed in separate CSS file used by template. The source code for the template will look like this:
<?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:f="http://java.sun.com/jsf/core">
    
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Bike Shop 2.0</title>
    </h:head>
    
    <h:body>
        <div id="container">
            <div id="top">
                <!-- logo and name goes here -->
            </div>
            <div id="leftnav">
                <h:form>
                    <!-- links goes here -->
                </h:form>
            </div>
            <div id="content">
                <ui:insert name="content" />
            </div>
            <div id="footer">
                ####
            </div>
        </div>
     </h:body>   
</html>

Please note the element <ui:insert name="content" /> inside the div named "content". It represents variable content which will be displayed in this place. Pages bikesShop.xhtml, bikesList.xhtml and bikeDetails.xhtml will "inject" here their content using special syntax. Let's have a look how bikesShop.xhtml page display its content using the template. Here is the code for bikesShop.xhtml:
<?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:f="http://java.sun.com/jsf/core">
  <ui:composition template="shopTemplate.xhtml">
       
        <ui:define name="content">
         Lorem ipsum dolor sit amet...
        </ui:define>

  </ui:composition>
</html>

First note that bikesShop.xhtml page have no <head> or <body> tags - they are defined in the template. A special element <ui:composition template="shopTemplate.xhtml"> tells the page to use the mentioned template.
As I wrote, the template has a special section for inserting the variable content (<ui:insert name="content" />). The page bikesShop.xhtml defines content to be placed into that section by using the tag <ui:define name="content"> ... </ui:define>  - note that attribute name="content" is the same for  <ui:insert/> and <ui:define />. Pages bikesList.xhtml and bikeDetails.xhtml use the same mechanism (they have the same <ui:define /> tag in their source).
That's all about templates.

Simplified page navigation.
Every page navigation in JSF 1.x required a proper entry in faces-config.xml file. It was something like this:

<navigation-rule>
     <description>Welcome page to message page</description>
     <from-view-id>/index.jsp</from-view-id>
     <navigation-case>
       <from-outcome>helloMessage</from-outcome>
       <to-view-id>/message.jsp</to-view-id>
    </navigation-case>
   </navigation-rule>

JSF 2.0 provides a simplified navigation model - we do not need any entries (navigation rules) in the faces-config.xml file. Why?
Suppose we have a method used for navigation which returns some string value. This string value (known as outcome) is taken by a navigation handler and the handler checks for navigation rules in faces-config.xml which have defined the same from-outcome value. When the rule is found, it is applied and a proper navigation is done. This is how it worked in JSF 1.x and how it works in JSF 2.0. But JSF 2.0 navigation handler does additional operation here: if no matching from-outcome value is found in faces-config.xml (in other words: there is no navigation rule to apply), handler checks also existing pages names (view identifiers). If existing page name matches returned outcome value, the navigation is done to that page.
For example if we have a navigation method in some backing bean:
public String getBikes(){
   bikesList = ... // load some bikes
   return "bikesList";
}
and there is a page named bikesList.xhtml, invoking this method will cause the navigation to that page - without defining proper navigation rule in faces-config.xml.

-------------------------------------------
Download source files:

The complete working example of mentioned application which will contain all described features, will be available in the last (third) article of this serie.

No comments: