Develop an application with Apache Derby, Apache MyFaces, and Facelets

Craft Java-based MVC Web apps with this powerful trio

Learn how to develop a Java™Server Faces (JSF) application using Apache Derby, Apache MyFaces, and Facelets. The ready-to-download sample application in this article uses a Model-View-Controller (MVC) architecture to illustrate the power of the MyFaces components and the ease of developing with Apache Derby and the latest view technology, Facelets.

What are JSF, Facelets, and Apache Derby?

The three technologies used in the Web application demonstrated in this article are JSF, Facelets, and Java Database Connectivity (JDBC), which is used to access data stored in Apache Derby, a relational database. JSF is a Web application framework for building user interfaces (UIs), while Facelets is a presentation technology designed specifically for use with JSF. Apache Derby is the 100% Java JDBC-compliant database. The use of these three components together provides a perfect environment for developing Java-based MVC Web applications.

When JSF was first introduced, it addressed the need for cleaner separation between the controller and the view layers of MVC Web applications. It also associated events with the server side, instead of having to rely solely on client-side JavaScript for event handling. However, the major contribution of JSF is its component-based model, which promotes reusability and extensibility. One of the down sides to using JSF was the technology used for the rendering layer, which by default was provided by JavaServer Pages (JSP). JSP is not a component-based system, therefore it cannot take advantage of all of the capabilities of JSF's model. The JSP tags in a JSF application render the view and represent the component, but cannot change the state of a JSF component.

Facelets

This is where Facelets comes in. Facelets was designed specifically taking into account JSF's component-based technology by producing its own component tree used in the view of a Web application. JSPs are compiled to create a servlet and are used to render dynamic content, but this content is not always in sync with the component tree JSF produces. Facelets works and integrates with the JSF component tree so there are no surprises in the output rendered -- which can occur when using JSP to render in JSF.

The sample application discussed in this article, and available in the Downloads section at the end of this article, makes use of Facelets' templating capabilities and shows an example of the improved error messages available when developing with Facelets. Many more features of Facelets are available, which won't be discussed in this article. (See Resources to learn more about them.)

JSF using Apache MyFaces

The MyFaces project at Apache provides an open source implementation of the JSF Web application framework specification JSR 127 (see Resources). MyFaces provides all of the classes required by the spec, as well as some additional JSF components called Tomahawk. Some of these components provide new functionality above and beyond those required by the spec, and some provide enhanced functionality.

You should be familiar with the ideas behind JSF to get the most out of this article. The excellent series by Rick Hightower listed in the Resources section is a great place to start.

Apache Derby

Apache Derby is used in the Model layer in the sample application, which is a fictitious flight reservation system. Apache Derby is the zero-admin, 100%-Java relational database, which is a perfect fit for Java-based Web application development because of its embeddable ability and JDBC standards compliance.

The focus of this article is how to use MyFaces, Facelets, and Derby together to build a Web application; it assumes you understand the basics of Web application development, JSF, and database access via JDBC.


Components of the Web application

The flight reservation application uses the following software components and technologies; the list also includes some of the specific features utilized in the application.

  • Apache MyFaces JSF Implementation 1.1.4 Core and Tomahawk 1.1.3
    • Validators -- This includes regular expression, Equals, and Credit Card validation.
    • updateActionListener— This listener can be associated with an ActionSource UIComponent (a link or button) to associate a value with a property.
    • Extended DataTable— This extends the standard JSF datatable with a header, which allows for sorting by column.
    • JavaScript Menu — The JSCookMenu component creates menu items using CSS and JavaScript to create dynamic menus.
  • Apache Derby database engine 10.1.3.1
    • Using the Derby EmbeddedDataSource
    • Starting and Stopping Derby via a ServletContextListener
    • JDBC Callable Statement to execute a stored procedure for writing SQL statements to Derby's message log file
    • JDBC Prepared Statements to insert and delete records from Derby.
  • Facelets -- JSF View Definition Framework 1.1.11
    • Templating — The ability to create a template for page code reuse and substitution.
    • Improved error messages — For easier debugging.
  • Apache Tomcat servlet engine 5.0.28
    • Runs the Web application consisting of the Extensible Hypertext Markup Language (XHTML) pages, servlet filters and listeners, and the JSF components.

Software requirements

The software described in this section is available for download at no cost and must be installed prior to running the sample Web application.

  1. Either of the following Java development kits:
    • IBM SDK V1.5 or later.
    • Sun JDK V1.5 or later.
  2. Apache Tomcat. Download V5.0.28 (see Resources).
  3. Facelets, JSF View Framework. Download V1.1.11 (see Resources).
  4. tagHandlers-0.9.jar contains the tag library class required to use the Tomahawk component, <t:updateActionListener>, with Facelets (see Resources).
  5. The sample application source code and Web application ZIP file:
    • Download Apache_Derby_MyFaces_Demo.zip to your file system (see the Download section). This includes all the src files and Web application files. The additional libraries you downloaded above are also required to run the app.

Software installation

After downloading all required components, install them (if you haven't already done so) using the following steps. You'll find out more about the configuration and get a detailed explanation of each component later on.

  1. Install a JDK. If you don't have a V1.5 or later JDK, install it. A JDK is required to run Tomcat.
  2. Install Apache Tomcat. Extract or install Apache Tomcat.
  3. Extract facelets-1.1.11.zip to a directory. You'll copy three of the Facelets JAR files to the WEB-INF/lib directory later on.
  4. Extract Apache_Derby_MyFaces_Demo.zip. This creates a top level directory, Flight_Reservation and the following subdirectories:
    • src— The packages of all of the Java source files used in the application:
      • org.apache.derby.demo.beans.model and org.apache.derby.demo.beans.view— The JSF managed bean classes and other Java bean classes that represent the underlying Model (database tables).
      • org.apache.derby.demo.filters— The LoginFilter class that implements javax.Servlet.Filter interface.
      • org.apache.derby.demo.persistence— The DataFactory ServletContextListener, DatasourceObject interface, and the DerbyDatabase class that implements the DatasourceObject interface.
      • org.apache.derby.demo.resource— The ErrorMessages class makes error messages available to the application via a resource bundle (properties file).
      • org.apache.derby.demo.validators— The ForwardDates is a custom JSF validator class, which ensures the date a flight is booked is either today or a future date.
    • Derby_MyFaces -- This is the directory that contains all libraries (except the ones you downloaded above), classes, configuration files, and XHTML files for the Web application.
    • Licenses -- For the third-party libraries contained in the Web application.

Before you get into the details of the application, a brief explanation of the architecture is helpful to understanding how everything fits together. The flight reservation demo is based on an earlier application I wrote for "Build Web applications with Eclipse, WTP, and Derby" (developerWorks, September 2005). The architecture has been changed and improved to use JSF and Facelets for the Controller and View layers instead of servlets and JSPs; also the need to configure Tomcat to use Derby as a data source has been alleviated. The JSF and Facelets component-based approach used in this article represents an improvement in the ease of development as well as the finished product over a more traditional Servlet and JSP approach.


Flight reservation system architecture

The Apache Derby and MyFaces flight reservation system is a simplified flight-booking application that allows users to:

  • Log in to the application.
  • Create an account.
  • View available flights based on date and departure city.
  • Select a destination airport based on departure city and date.
  • Book a flight by providing credit card information.
  • View all flights booked per user.
  • Log out of the application.

Design and technologies used

Figure 1 shows an overview of the design of the flight reservation application in terms of the technologies and components used, as well as some of the implementation-specific file names and libraries.

Figure 1. Technologies, components, and implementation of the flight reservation application
Technologies, components, and implementation of the flight reservation application

The View — Facelets

The View layer is implemented using Facelets technology and XHTML Web pages. To use Facelets, jsf-facelets.jar needs to be included in the Web application. Being able to use XHTML for the presentation layer instead of JSP aids in the development process, because the page can be validated using any XML tool, plus picking up XHTML syntax is usually easier than JSP syntax.

The Controller

The Controller is made up of the JSF layer with servlet listeners and filters that are unrelated to JSF but enhance the functionality of the Web application.

JSF — MyFaces

Figure 1 shows a partial listing of the Java classes that are controlled by the managed bean facility in JSF. The application uses a few of the Tomahawk validators and a custom validator class. As is usual in a JSF application, navigation is mapped out in the faces-config.xml file. The components used in the XHTML pages are some of the standard JSF components, like html form and html PanelGroup, and some of the Tomahawk components, like inputCalendar, which displays a calendar for selecting a day of the month, and selectOneListbox.

Making use of Web application life cycle events

The flight reservation system uses of Web application life cycle events available to the servlet container, in this case Apache Tomcat 5.0, to initialize a data source and the JSF environment and to force users to log in prior to using the application.

Two servlet filters are used, the LoginFilter class, which routes all requests for the application via the Login page, and the MyFaces ExtensionsFilter, which is used to load external resources required by some of the Tomahawk components, such as images and JavaScript files.

The servlet context listeners used in the application are the MyFaces StartupServletContextListener, used to initialize the JSF environment, and a DataFactory application class, which is used to read a properties file to dynamically configure the data source used. In this application, Apache Derby is used as the data source via the Derby EmbeddedDataSource implementation of the javax.sql.DataSource interface. However, the design of the application allows for flexibility to plug in another data source — for instance, Java Persistent Objects (JPOX), which implements the Java Data Objects (JDO) specification, could be used with Derby as the back end instead of direct access to the database via JDBC.

Because the DataFactory class implements the ServletContextListener interface, it guarantees that its init method is called when the servlet context is first created. You'll examine this class in more detail later on, but initializing database resources via a class that implements the ServletContextListener interface ensures these resources are available for the entire life cycle of the Web application.

The Model

The Model layer includes the Derby database engine, consisting of a single .jar file, derby.jar. The POJO class that is used to make the JDBC calls to Derby is called DerbyDatabase, which implements the DatasourceObject interface, another application class.


Running the application

Copy the Web application to the Tomcat webapps directory

Having trouble running the application?

  1. Make sure you copied the four extra libraries — jsf-facelets.jar, el-api.jar, el-ri.jar, and tagHandlers-0.9.jar -- to the %TOMCAT_HOME%/webapps/Derby_MyFaces/WEB-INF/lib directory.
  2. Did you stop and restart Tomcat?
  3. For help troubleshooting, look at Tomcat's console and the logs.
  4. If you get the error message HTTP 500 javax.servlet.ServletException: net/sf/jsfcomp/facelets/taghandlers/ tomahawk/UpdateActionListenerHandler (Unsupported major.minor version 49.0) when you try to bring up the first page of the application, it means you didn't start Tomcat with a 1.5 JDK. Install JDK 1.5 if you haven't done so, and make sure your JAVA_HOME environment variable points to this installation before you start up Tomcat.

Copy the entire Derby_MyFaces directory from the Flight_Reservation directory created when you extracted the .zip file to your %TOMCAT_HOME%/webapps directory.

All of the Apache 1.1 and 2.0 licensed JAR files are already present and bundled with the application; however, four additional JAR files you already downloaded need to be added.

All of the following JAR files need to be copied to the %TOMCAT_HOME%/webapps/Derby_MyFaces/WEB-INF/lib directory:

  • jsf-facelets.jar from the facelets-1.1.11 directory
  • el-api.jar and el-ri.jar from the facelets-1.1.11/lib directory
  • tagHandlers-0.9.jar from the location you downloaded it to in the Software requirements section

Now you can bring up the application to make sure you have all the software installed correctly and everything has been copied to the correct location. Start up Tomcat, and open a browser to the URL http://<hostname>:<port>/Derby_MyFaces/, substituting hostname and port with your environment.

When I installed Tomcat, I used the standard configuration, so in my environment the URL is http://localhost:8080/Derby_MyFaces/.

The first page of the application is shown in Figure 2, with the values of apacheu entered for the user name and password.

Figure 2. First page of the flight reservation demo application
First page of the flight reservation demo application

Go ahead and enter apacheu for the user name and password on your system, and click the Submit button. This tests the connection to the Derby database since these values represent a row in the USERS table, and a select against this table will be made to verify that these values are correct. The Derby database called airlinesDB was installed as part of the Web application. In Derby, a database is represented on disk as a directory. If the configuration is correct, the next page of the application allows you to select a departure date and an origination airport, as shown in Figure 3.

Figure 3. Selecting the departure date and origination airport, SelectDateAirport
Selecting the departure date and origination airport, SelectDateAirport

Before going further in the application, take a look at some of the classes used behind the scenes thus far in the Model layer.


The Model — Derby data source

The three application classes used for the data source are:

  • DatasourceObject.java
  • DerbyDatabase.java
  • DataFactory.java

Note: In this article, the term data source is a general reference of a source of data. When referring to a class that implements the javax.sql.DataSource interface or the interface itself, the interface name is used.

Browse to the directory where you extracted the Flight_Reservation.zip file, and look in the org/apache/derby/demo/persistence directory under the Flight_Reservation/src directory if you'd like to examine these Java files more closely.

Earlier I mentioned that the design of the application lends itself to an extensible architecture by allowing other data sources to be used. To do so, the data source needs to implement the DatasourceObject interface, which is shown in Listing 1.

The initialize method is for initializing and starting the data source, and the shutdown method is for stopping or shutting down the data source.

Listing 1. The DatasourceObject interface
package org.apache.derby.demo.persistence;

public interface DatasourceObject {

  public void initialize(String pathtoResource);

  public void shutdown();

  public boolean checkUserName(String userName);

  public UserBean getUserPassword(String userName);

  public int insertUser(String firstName, String lastName, String userName,
			String email, String password);

  public int insertUserCreditCard(String lastName, String userName,
			String creditCardType, String creditCardNum,
			String creditCardDisplay);

  public CityBean[] destAirports(String origAirport);

  public CityBean[] cityList();

  public FlightsBean[] origDestFlightList(String origAirport,
			String destAirport, Date beginDate);

  public FlightHistoryBean[] fetchFlightHistory(String userName);

  public int insertUserFlightHistory(String userName,
     FlightsBean flightsBean, String creditCardType, String creditCardNum);

}

Listing 2 shows the initialize method of the DerbyDatabase class, which is a requirement of implementing the DatasourceObject interface.

Listing 2. The initialize method of the DerbyDatabase class
public class DerbyDatabase implements DatasourceObject {

  private static EmbeddedDataSource ds = null;

  ...

  private static final String databaseName = "airlinesDB";

  public void initialize(String filePathToWebApp) {
    if (isInitialized) {
      return;
    }

    try {
      if (ds == null) {
        ds = new EmbeddedDataSource();
        ds.setDatabaseName(filePathToWebApp + "/" + databaseName);

        // Call this method only during development
	logStatements();
      }
    } catch (Exception except) {
     except.printStackTrace();
    }

    isInitialized = true;
  }
  ...
}

The initialize method creates an org.apache.derby.jdbc.EmbeddedDataSource, sets the database name for the javax.sql.DataSource to use by appending the database name to the full path of the Web application, and then calls the logStatements method. This method is covered later.

What calls the DerbyDatabase initialize method, which actually creates the DataSource? This is where a Web application life cycle event comes into play. The DataFactory class appearing in Listing 3 implements the ServletContextListener interface, and therefore must provide an implementation of the contextInitialized method, which is called by the Web container when the Web application is first loaded.

The contextInitialized method calls the init method of the DataFactory class. This, in turn, calls the createDatasourceObject method that reads the properties file, looking for the string datasource-type, and creates an instance of this type. In this application there is only one entry in this properties file, shown below, but by implementing the DatasourceObject interface, other implementations are possible:

datasource-type=org.apache.derby.demo.persistence.DerbyDatabase

After an implementation of the DatasourceObject interface is created, this implementation's initialize method is called, as shown in the initializeDatasourceObject method (see Listing 3). This brings you right back to your DerbyDatabase initialize method, shown in Listing 2.

Listing 3. Creating the data source via the DataFactory class
public class DataFactory implements ServletContextListener {

  public static final String DATASOURCEOBJECT_TYPE = "datasource-type";

  private static final String FACTORY_CONFIG = "factory.properties";

  private ServletContext servletContext;

  private static DatasourceObject datasourceObject;
  
  ...

  private synchronized void init() {

    if (isInitialized)
      return;

    createDatasourceObject();

    initializeDatasourceObject(servletContext.getRealPath(""));

    isInitialized = true;
  }

  private void createDatasourceObject() {

    InputStream is = this.getClass().getResourceAsStream(FACTORY_CONFIG);

    prop = new Properties();
    try {
      prop.load(is);
    } catch (IOException exception) {

    throw new RuntimeException(Messages
     .getString("FACTORY_CONFIG_NOT_FOUND"), exception);

    }

    String datasourceType = prop.getProperty(DATASOURCEOBJECT_TYPE);

    if (datasourceType == null)
      throw new RuntimeException(Messages
        .getString("DATASOURCEOBJECT_TYPE_NOT_FOUND"));

      datasourceObject = (DatasourceObject) createInstance(datasourceType,
				DatasourceObject.class);

  } 

  ...

  private void initializeDatasourceObject(String pathToResource) {
    datasourceObject.initialize(pathToResource);
  }
  ...

  public void contextInitialized(ServletContextEvent sce) {
    servletContext = sce.getServletContext();
    System.out.println("contextInitialized called in 
     org.apache.derby.demo.persistence.DataFactory");
    init();
  }

  ...

  public void contextDestroyed(ServletContextEvent sce) {
    datasourceObject.shutdown();
  }
}

By providing an implementation of the contextInitialized method of the ServletContextListener interface, the implementation of the DatasourceObject interface is created — in this case the DerbyDatabase class — and initialized as the Web application is first loaded and is therefore ready when the first request to this Web application is made.

In Listing 2, the logStatements method was called in the initialize method of the DerbyDatabase class. This method should only be used in a development environment when you want to log the database queries made in the application to the derby.log, the message file for Derby. It's included here to illustrate the use of an SQL CallableStatement invoked via the SQL CALL syntax, as shown in Listing 4.

Listing 4. The logStatements and getUserPassword methods of the DerbyDatabase class
  /* call this method only during development
   * logs all sql statements to derby.log for debugging purposes
   */

  public void logStatements() {
    String query = "CALL 
     SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.language.logStatementText', 'true')";
    Connection conn;

    try {
      conn = ds.getConnection();
      CallableStatement cs = conn.prepareCall(query);
      cs.execute();
      cs.close();
      conn.close();
    } catch (SQLException sqlExcept) {
        sqlExcept.printStackTrace();
      }
  }

  public UserBean getUserPassword(String userName) {
    String query = "select username, password from APP.USERS where username = ?";
    UserBean userBean = new UserBean();
    Connection conn;

    try {
      conn = ds.getConnection();
      PreparedStatement prepStmt = conn.prepareStatement(query);
      prepStmt.setString(1, userName);
      ResultSet results = prepStmt.executeQuery();

      while (results.next()) {
        String username = results.getString(1);
	String password = results.getString(2);
	userBean.setUserName(username);
	userBean.setPassword(password);
	}

	results.close();
        prepStmt.close();
        conn.close();
    } catch (SQLException sqlExcept) {
        System.out.println("Exception in getUserPassword");
	sqlExcept.printStackTrace();
      }

    return userBean;

  }

  ...
}

Listing 5 shows a snippet of the output in the derby.log file when the Derby system procedure, SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY is called. It shows a select of the USERS table with one parameter, apacheu.

Listing 5. derby.log output from calling the system procedure SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY
...
2006-08-25 00:04:42.139 GMT Thread[http-8080-Processor24,5,main] (XID = 1439), 
(SESSIONID = 1), 
(DATABASE = C:/jakarta-tomcat-5.0.28/webapps/Derby_MyFaces/airlinesDB), 
(DRDAID = null), 
Begin compiling prepared statement: select username, password from APP.USERS 
where username = ? 
:End prepared statement
2006-08-25 00:04:42.369 GMT Thread[http-8080-Processor24,5,main] (XID = 1439), 
(SESSIONID = 1), 
(DATABASE = C:/jakarta-tomcat-5.0.28/webapps/Derby_MyFaces/airlinesDB), 
(DRDAID = null), 
End compiling prepared statement: select username, password from APP.USERS 
where username = ? 
:End prepared statement
2006-08-25 00:04:42.399 GMT Thread[http-8080-Processor24,5,main] (XID = 1439), 
(SESSIONID = 1), 
(DATABASE = C:/jakarta-tomcat-5.0.28/webapps/Derby_MyFaces/airlinesDB), 
(DRDAID = null), 
Executing prepared statement: select username, password from APP.USERS where username = ? 
:End prepared statement 
with 1 parameters begin parameter #1: apacheu :end parameter 
2006-08-25 00:04:42.439 GMT Thread[http-8080-Processor24,5,main] (XID = 1439), 
(SESSIONID = 1), 
(DATABASE = C:/jakarta-tomcat-5.0.28/webapps/Derby_MyFaces/airlinesDB), 
(DRDAID = null), Committing
...

The getUserPassword method shown in Listing 4 is one of the methods required by the DatasourceObject interface. It shows the standard way to make a query to the Derby database using an SQL PreparedStatement, and as you've probably already figured out, this was the method called when you entered your user name and password on the first page, which produced the output in the derby.log file!

The shutdown method of the DerbyDatabase class shown in Listing 6 demonstrates how to shut down the airlinesDB started by Tomcat. The setShutdownDatabase method is called with the string "shutdown", and then a call to getConnection is required to actually perform the shutdown. When Derby shuts down a database, it throws an SQLException with an SQLState of 08006, which is why the catch block ignores this exception.

Listing 6. Shutting down the airlinesDB Derby database
public void shutdown() {
  if (isShutdown) {
    return;
  }
  try {
    ds.setShutdownDatabase("shutdown");
    // necessary to actually shut down the derby database
    ds.getConnection();
  } catch (SQLException except) {
    if (except.getSQLState().equals("08006")) {
      // ignore, this is the SQLState derby throws when shutting down the database
      System.out.println("Derby database shut down.");
      isShutdown = true;
    }
    else {
      except.printStackTrace();
    }
  }
}

Similar to how the initialize method of the DerbyDatabase class is called using the contextInitialized Web life cycle event, the shutdown method in Listing 6 is called by the contextDestroyed life cycle event in the DataFactory class shown below. Therefore, when Tomcat is shutting down and unloading the Web application, the shutdown method of the class implementing the DatasourceObject interface is called, shown here:

public void contextDestroyed(ServletContextEvent sce) {
datasourceObject.shutdown();
}

This covers most of the interesting details of the Model layer. Next you'll examine the Controller.


The Controller — Life cycle events and servlet filters

In the previous section, you learned how to use the contextInitialized and contextDestroyed methods, which are called as part of creating and destroying Web applications in the setting of initializing your Model layer. So, although I consider these to be part of the Controller layer, they were discussed in the Model section of this article.

Servlet filters can also be considered part of the Controller layer of a Web application. In general, servlet filters are used to control the flow of the application based on user type (or authentication and authorization) or page functionality. The servlet container provides a javax.servlet.FilterChain object that can be used to invoke the next filter in the chain. To register a filter as part of a Web application — and therefore to have its doFilter method called as part of the FilterChain— it must be added to the web.xml file of the application.

Your web.xml file has this entry for your LoginFilter class, which implements the javax.servlet.Filter interface. These entries mean that anything with a URL pattern of *.jsf or /Derby_MyFaces/* will be subject to the LoginFilter class (see Listing 7).

Listing 7. The LoginFilter entry in the web.xml
<filter>
  <filter-name>login</filter-name>
  <filter-class>org.apache.derby.demo.filters.LoginFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>login</filter-name>
  <url-pattern>*.jsf</url-pattern>
</filter-mapping>

<filter-mapping>
  <filter-name>login</filter-name>
  <url-pattern>/Derby_MyFaces/*</url-pattern>
</filter-mapping>

Listing 8 shows the LoginFilter class, which does the following:

  • If a request is made for the Registration page, Register.jsf, directly, send the request to this page without calling any other servlet filters in the FilterChain object.
  • If the session attribute "login-status" is true, allow the request to proceed by calling the next filter in the chain.
  • If the session attribute "login-status" is null, or not true, forward the request to the login page, Welcome.jsf, without calling the next filter's doFilter method in the chain.
Listing 8. LoginFilter class
public class LoginFilter implements Filter {

  private FilterConfig config;

  private RequestDispatcher dispatcherLogin;

  private RequestDispatcher dispatcherRegister;

  private static final String LOGIN_PAGE = "/login/Welcome.jsf";

  private static final String REGISTER_PAGE = "/login/Register.jsf";

  public static final String AUTH_STATUS = "login-status";

  public void init(FilterConfig filterConfig) throws ServletException {

    config = filterConfig;

    dispatcherLogin = config.getServletContext().getRequestDispatcher(LOGIN_PAGE);

    dispatcherRegister = config.getServletContext().getRequestDispatcher(REGISTER_PAGE);

    } 

  public void doFilter(ServletRequest req, ServletResponse res,
      FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;

    // if a request is made directly for Register.jsf send them to it
    if (request.getServletPath().equals(REGISTER_PAGE)) {
      dispatcherRegister.forward(req, res);
    }
    // otherwise if their login-status is not null
    else if (request.getSession(true).getAttribute(AUTH_STATUS) != null) {
      // if it is true, send them on to the next filter in the chain
      if (request.getSession(true).getAttribute(AUTH_STATUS) == Boolean.TRUE) {
        chain.doFilter(req, res);
        // otherwise send them to the login page
      } else {
        dispatcherLogin.forward(req, res);
      }
    }
    // if login-status is not set at all send them to the login page
    else {
      dispatcherLogin.forward(req, res);
    }

}

The Controller -- JSF using Apache MyFaces

Page flow and navigation

Looking back at Figure 1, JSF is at the heart of the Controller layer in this application. A good place to start to understand the flow of an application is the JSF configuration file, faces-config.xml. (If you're not familiar with JSF and don't understand the purpose of the faces-config.xml file, refer to the Resources area for a link to learn the basics of JSF.)

In brief, here you'll examine the navigation directives in this file, which map specific actions or outcomes to allow navigation to a page. The page flow and functionality of each page in the application is listed below.

  1. Welcome.xhtml: Logs in existing users.
  2. Register.xhtml: Registers a new user.
  3. SelectDateAirport.xhtml: Selects departure date and originating airport.
  4. DestinationAirport.xhtml: Shows destination airports based on the originating airport, and allows you to select one.
  5. FlightList.xhtml: Shows available flights based on the selected destination and origination airports.
  6. CreditCard.xhtml: Allows users to enter credit card information based on the selected flight.
  7. FlightHistory.xhtml: Shows all flights booked by this user.
  8. LoggedOut.xhtml: Logs out of the application.

Figure 4 shows a graphical representation of the navigation portion of the faces-config.xml file.

The pages in the upper half of Figure 4 deal with registration, logging in, and logging out. To follow the page flow pertaining to selecting, booking, and paying for a flight, look in the lower half, starting in the left quadrant, and then in the lower-right quadrant, starting at the top.

As an example of interpreting this figure, find the orange block that represents the /flights/SelectDateAirport.xhtml page. The two arrows pointing to it represent two acceptable outcomes, one of which must occur prior to the page being served, namely logged_in and back_to_flights. These are the required outcomes shown in the textual representation of the faces-config.xml file in Listing 9. In the next section you'll see how to obtain one of the required outcomes.

Figure 4. Page navigation in the faces-config.xml file
Page navigation in the faces-config.xml file
Listing 9. Two navigation cases from faces-config.xml for the SelectDateAirport page
<navigation-case>
    <from-outcome>logged_in</from-outcome>
    <to-view-id>/flights/SelectDateAirport.xhtml</to-view-id>
</navigation-case>

<navigation-case>
    <from-outcome>back_to_flights</from-outcome>
    <to-view-id>/flights/SelectDateAirport.xhtml</to-view-id>
</navigation-case>

Managed beans, actions, and outcomes

The managed bean creation facility of JSF automatically creates a bean, initializes it, and stores it in the proper scope when referenced. After a bean is created and no longer used, it's returned to this facility.

One of the big pluses of the managed bean facility is the ability to reference beans using JSF's expression language syntax, which you'll see used in most of the XHTML pages.

Let's look at one of the managed beans for the application associated with producing the <from-outcome> in Listing 9. Listing 10 shows another snippet of the faces-config.xml file, showing the loginBean, where all managed beans used in the JSF application must be described.

Listing 10. All managed beans used in the JSF application must be described in the loginBean
<managed-bean>
  <managed-bean-name>loginBean</managed-bean-name>
  <managed-bean-class>org.apache.derby.demo.beans.model.LoginBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

The bean has session scope, which makes sense for something used to track if the user is logged in or not. When the user's session ends (either by logging out or closing the browser window), the bean must be recreated for that user.

The authenticate method for the loginBean is shown in Listing 11. This is the method called when the Submit button is pushed in Figure 2.

Listing 11. Partial listing of the LoginBean class
public class LoginBean implements Serializable {

  private String username;

  private String password;

  private String loggedIn = "false";

  public LoginBean() {
    username = "";
    password = "";
  }

  public LoginBean(String userName, String passWord) {
    username = userName;
    password = passWord;
  }

  // verify if the username already exists
  // verify if the username and password match what is in the data source
  public String authenticate() {
    String result = "failure";
    FacesContext context = FacesContext.getCurrentInstance();
    DatasourceObject datasourceObject = DataFactory.getDatasourceObject();

    // create a UserBean by retrieving the username and password from
    // the database if the username entered on the page is in the db
    UserBean userBean = datasourceObject.getUserPassword(username);
    String userName = userBean.getUserName();

    // verify the name entered on the page and the one in the db
    // are the same
    if (userName != null && userName.equals(username)) {

      String actualPassword = userBean.getPassword();
      // verify the passwords are the same
      if (actualPassword != null && actualPassword.equals(password)) {
        // set the session attribute LoginFilter.AUTH_STATUS to true
        ((HttpSession) context.getExternalContext().getSession(true))
          .setAttribute(org.apache.derby.demo.filters.LoginFilter.AUTH_STATUS,
				Boolean.TRUE);
        setLoggedIn("true");
	// set 'result' to "logged_in" which maps to the faces-config navigation case
	// for the /flights/SelectDateAirport.xhtml <from-outcome> value.
        result = "logged_in";
      }
      // the userName and the username match ... but the passwords don't
      else {
        String failureMsg = ErrorMessages.getString("LoginBean.LOGIN_FAILURE");
	FacesMessage message = new FacesMessage(
	    FacesMessage.SEVERITY_ERROR, failureMsg, failureMsg);
	context.addMessage("login_form:loginButton", message);
      }
      // the userName is not null but it does not match the username
    } else {
      String failureMsg = ErrorMessages.getString("LoginBean.LOGIN_FAILURE");
      FacesMessage message = new FacesMessage(
        FacesMessage.SEVERITY_ERROR, failureMsg, failureMsg);
      context.addMessage("login_form:loginButton", message);
    }
    return result;
    }  
 ...

The getUserPassword method is called on the DatasourceObject, which, in this case, is the DerbyDatabase class to create a UserBean. This UserBean represents either a single row returned from the Derby database or no rows, depending on whether the user name entered in the form matches a user name in the database. If a row is returned from the database, the UserBean is populated with non-null user name and password member variables.

If a row is retrieved from the database, it means the userName variable and actualPassword variables are not null. Both of these are compared to the values from the form. If they match, an attribute is set in the user's session to indicate that they are logged in. Remember how this session attribute (Listing 8) was examined in the doFilter method? The authenticate method is where it was set. Finally, the String variable result is set to logged_in because authentication is successful. (If not, it remains set to the value of failure).

This value, logged_in, is the required value you looked at in Listing 9, which allows navigation to the next page, /flights/SelectDateAirport.xhtml, shown in Figure 3.

MyFaces validators

Validation of form entries in a Web app ensures data is in the correct format or range prior to processing data; for instance, prior to inserting a value into the database. The flexibility of use and the ability to associate error messages with the component being validated is a desirable characteristic of the way JSF handles validation. The MyFaces implementation of JSF, specifically the Tomahawk components, include ready-to-use validators, alleviating the need to write a custom validator for many common data entry types.

Looking at the first page of the application shown in Figure 2, you had the option to register a new user. Clicking the Register button brings you to the Register.xhtml page. Figure 5 shows the results of filling out the text fields with incorrect values and the results of clicking the Submit button. The validateRegExpr, validateEmail, and validateEqual Tomahawk components are used on this page.

Figure 5. Validation using the MyFaces Tomahawk validators
Validation using the MyFaces Tomahawk validators

To understand the use of the regular expression validator and the associated error message displayed for the lastname text field, look at this snippet of source code from Register.xhtml, shown in Listing 12.

Listing 12. Partial source code from Register.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<t:document 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:t="http://myfaces.apache.org/tomahawk">
...

<h:form id="register_form">
 ...

<h:outputLabel for="lastname" styleClass="standard" 
   value="#{messages['register_lastname']}" />
<h:inputText id="lastname" value="#{userBean.lastName}" required="true" maxlength="40">
  <t:validateRegExpr pattern='[a-zA-Z]+' />
</h:inputText>
<t:message id="lastNameError" for="lastname" styleClass="error" />
...

</h:form>

The JSF HTML tag <h:outputLabel> specifies the component it's associated with, the CSS style to use for the label, and the value of the label retrieved from a message bundle called messages.

The HTML inputText field has an ID of lastname and assigns the value for this text field to the lastName property of a UserBean. The next line shows the use of the Tomahawk validateRegExpr validator and the regular expression pattern used to enforce the validation. Here, the string for the text field must be any alpha character whose length is one or more characters up to a maximum of 40, as specified in the inputText maxlength attribute.

The Tomahawk message component must be associated to another component for which it reports the error. This is done using its for attribute, which matches the id attribute of the associated component. Now it's clear why the value !Cline for the text field was not allowed and why the error message was reported in red, the color for the CSS error style, on the page.

The nice thing about the regular expression is the ability to customize the regular expression used. For instance, for the username and password text fields, I specified the pattern pattern='[a-zA-Z0-9]+' for the regular expression, which increases the flexibility and usability of this component for multiple situations.

Multiple validators can be used for the same component, as shown in Listing 13 for the passwordVerify inputSecret tag. (Line breaks added for readability.)

Listing 13. Multiple validators used for the same component
<h:outputLabel for="password" styleClass="standard" 
   value="#{messages['register_password']}" />

<h:inputSecret id="password" value="#{userBean.password}" required="true" maxlength="20">
  <t:validateRegExpr pattern='[a-zA-Z0-9]+'>
</h:inputSecret>

<t:message id="passwordError" for="password" styleClass="error" />

<h:outputLabel for="passwordVerify" styleClass="standard" 
  value="#{messages['register_password_verify']}" />
<h:inputSecret id="passwordVerify" value="#{userBean.passwordVerify}" required="true" 
    maxlength="20">
  <t:validateRegExpr pattern='[a-zA-Z0-9]+' />
  <t:validateEqual for="password" />
</h:inputSecret>

<t:message id="passwordVerifyError" for="passwordVerify" styleClass="error" />

More Tomahawk

Let's step through the application a little further before exploring more of the Tomahawk components. Continue where you left off in the application as the apacheu user. In Figure 3 you were about to select a flight on September 28 leaving from Toronto. Figure 6 shows the results of doing so.

Figure 6. Available flights leaving from Toronto
Available flights leaving from Toronto

There's nothing very remarkable about this page — it uses standard JSF components. You can look at the source of this page for yourself if you have installed the application. There's a link in the lower-right corner of each page that says Show Source. Selecting this link allows you to see the XHTML source for the currently displayed page.

Click the Go button from this page to advance to FlightList.xhtml. This page makes use of the Tomahawk dataTable, commandLink, and updateActionListener components.

Figure 7. Flight list for Toronto to London -- additional Tomahawk components
Flight list for Toronto to London -- additional Tomahawk components

For now, ignore the dataTable component in Listing 14; essentially it represents an HTML table with some additional functionality that will be discussed later on. Instead, take a look at the updateActionListener component nested in the commandLink component.

Listing 14. commandLink and updateActionListener components
...

<t:dataTable id="data" styleClass="scrollerTable" headerClass="standardTable_Header" 
 footerClass="standardTable_Header" rowClasses="standardTable_Row1,standardTable_Row2" 
 columnClasses="standardTable_ColumnCentered" var="flight"
 value="#{flightConfig.availableFlights}" preserveDataModel="true" rows="5">

 <h:column>
  <f:facet name="header">
   <h:outputText value="#{messages['flight_id']}" />
  </f:facet>
  <t:commandLink id="command_link" action="#{flight.selectedFlight}" immediate="true">
   <h:outputText value="#{flight.flightId}" />
   <t:updateActionListener property="#{flightBean}" value="#{flight}" />
  </t:commandLink>
</h:column>

...

The updateActionListener component must have an ActionSource (commandLink or commandButton) as its parent component. Here's what happens when the commandLink associated with the output text value of flightId for the flight variable is clicked:

  • The value for the commandLink action may be specified as a method binding, which, in this case, corresponds to the selectedFlight() method in the FlightsBean class. All this method does is return a string that is used as a navigation outcome for the next page. Look for the string get_selected_flight in Figure 4 to see which page will be navigated to.
  • The updateActionListener component assigns the value from its value attribute to its property attribute. This means the value contained in the flight variable is assigned to the managed bean, flightBean. The flight variable represents a single FlightsBean object from a java.util.List of FlightsBeans represented by the flightConfig bean's availableFlights variable. This is accomplished by the dataTable component, which iterates over the FlightsBeans contained in the availableFlights list and places each instance of FlightsBean in the variable flight.

Why is the updateActionListener component important here? The next page allows the user to book the flight once credit card information is obtained. Without being able to pass the specific flight (FlightsBean), this information is lost.

Figure 8 shows the result of selecting flight number US1592 from Toronto to London, filling out the credit card information, and clicking the Charge My Credit Card button.

Figure 8. Booking a flight
Booking a flight

Tomahawk CreditCard Validator

It's apparent there is a validator for the Credit Card field shown in Figure 8. The source for some of the CreditCard.xhtml page appears in Listing 15.

Listing 15. CreditCard.xhtml, validateCreditCard Tomahawk tag
...
<h:panelGrid columns="3">
 <h:outputLabel for="creditCardNumber" styleClass="standard" 
   value="#{messages['validate_credit']}" />
  <h:inputText id="creditCardNumber" value="#{creditBean.creditCardNumber}" 
    required="true" size="16" maxlength="16" immediate="true">
   <t:validateCreditCard amex="true" visa="true" mastercard="true" discover="false" />
  </h:inputText>
  <t:message id="creditCardNumberError" for="creditCardNumber" styleClass="error" />
...

<h:form id="validate_cc">
 <h:panelGrid columns="1">
  <h:selectBooleanCheckbox id="r2" value="#{creditBean.creditCardValidate}"  
   immediate="true" 
    onclick="submit()" valueChangeListener="#{creditBean.handleValidation}">
   <h:outputText value="#{messages['validate_cc']}" styleClass="standard"/>
  </h:selectBooleanCheckbox>
  <br/>
 </h:panelGrid>
</h:form>

The validateCreditCard component accepts five attributes -- the four shown in Listing 15, plus one called none. I'm willing to accept Amex, Visa, and MasterCard credit cards, but not Discover. This component uses Jakarta Commons Validation.

Note: This validation really works! Don't expect to be able to advance to the next page unless you disable validation or enter a valid credit card number.

The second snippet of code in Listing 15 makes use of an HTML selectBooleanCheckbox to dynamically handle disabling or enabling validation. The onclick attribute submits the value of the checkbox, #{creditBean.creditCardValidate}, a boolean, as soon as the event is fired because of the true value for the immediate attribute. The method called to receive this event is specified by the valueChangeListener attribute, the handleValidation method of UserCreditCardBean.

To test this, disable credit card validation by unchecking the Enable Validation of Credit Card check box, and then click the Charge My Credit Card button. To understand how the toggling of validation works, look at the handleValidation method in the UserCreditCardBean class in Listing 16, since this is the method called when the box is checked or unchecked.

Listing 16. UserCreditCardBean handling of dynamic validation
public void handleValidation(ValueChangeEvent event) {
  Object value = event.getNewValue();
		
  if (value == Boolean.TRUE) {
    enableValidateCC();
  }
  else {
    disableValidateCC();
  }
		
}
...
public String enableValidateCC() {

  FacesContext facesContext = FacesContext.getCurrentInstance();

  UIInput creditCardNumber = (UIInput) facesContext.getViewRoot()
   .findComponent("credit_card_form:creditCardNumber");
  Validator[] validators = creditCardNumber.getValidators();
  if (validators == null || validators.length == 0) {
    creditCardNumber.addValidator(new CreditCardValidator());
  }
  return "ok";
}
...
public String disableValidateCC() {

  FacesContext facesContext = FacesContext.getCurrentInstance();
		
  UIInput creditCardNumber = (UIInput) facesContext.getViewRoot()
   .findComponent("credit_card_form:creditCardNumber");
  Validator[] validators = creditCardNumber.getValidators();
  if (validators != null) {
    for (int i = 0; i < validators.length; i++) {
      Validator validator = validators[i];
      creditCardNumber.removeValidator(validator);
    }
  }

  return "disabled";
}

The new value associated with the event passed into the handleValidation method is used to determine whether to enable or disable credit card validation. This is the Boolean value of the checkbox component. The two methods, enableValidateCC and disableValidateCC, obtain the currentInstance of the FacesContext, then get the UIInput component corresponding to the creditCardNumber input text field (see Listing 15) and either add or remove the validator, depending on whether a call is made to enable or disable validation.

Tomahawk's extended DataTable and JSCookMenu components

After disabling credit card validation, I booked my flight from Toronto to London, and then I decided to book several other legs of my journey. Figure 9 shows the results of doing so. This page highlights the use of the Tomahawk extended DataTable and JSCookMenu components.

Figure 9. Flight history — JSCookMenu and a sortable DataTable
Flight history -- JSCookMenu and a sortable DataTable

The Tomahawk DataTable component adds two features to the standard JSF DataTable:

  • The ability to save the state of the DataModel, which is important if the data is backed by a database connection since the data in the database may have changed since the last request
  • Support for clickable sortable headers

Listing 17 shows some of the XHTML for the Tomahawk dataTable component in the FlightList.xhtml page. I've set the preserveDataModel attribute to true and specified value bindings to a FlightsHistory managed bean for the sortColumn and sortAscending attributes. Also notice the use of the Tomahawk commandSortHeader tag used within the dataTable tag. This component is derived from the commandLink actionSource component.

Listing 17. Partial XHTML for the Tomahawk dataTable component in the FlightList.xhtml page
<t:dataTable id="data" styleClass="scrollerTable" headerClass="standardTable_Header" 
  footerClass="standardTable_Header" rowClasses="standardTable_Row1,standardTable_Row2" 
  columnClasses="standardTable_ColumnCentered" var="bookedFlight"
  value="#{flightHistory.bookedFlights}" preserveDataModel="true" 
  rows="8" sortColumn="#{flightHistory.sort}" 
  sortAscending="#{flightHistory.ascending}" preserveSort="true">

  <h:column>
   <f:facet name="header"> 
    <t:commandSortHeader columnName="flight_id" arrow="true"> 
     <h:outputText value="#{messages['flight_id']}" /> 
    </t:commandSortHeader> 
   </f:facet>
   <h:outputText value="#{bookedFlight.flightId}" />
  </h:column>
...

How does the sort of the table work? When the Charge My Credit Card button was clicked (see Figure 8), it called the method submitCC() in the UserCreditCardBean class. This called the method findBookedFlights in the FlightsHistory class. This method populates a java.util.List with all of the booked flights for that user. Clicking one of the commandSortHeader links sorts the rows based on the values in this column. When this occurs, the bookedFlights need to be retrieved from the flightHistory bean. In doing so, it calls the getSort() method of the FlightsHistory class. The getSort() method sorts the list according to the header selected using a java.util.Comparator that is implemented in this class. To examine the code yourself, open up the FlightsHistory.java file.

Experiment with clicking the headers to see how the sorting works.

The last Tomahawk component you'll look at is JSCookMenu shown at the bottom of Figure 9. The Menu item Logout is highlighted. JSCookMenu uses JavaScript and CSS within the component to create nice-looking menu items.

The source from FlightHistory.xhtml where the JSCookMenu tag is used is shown in Listing 18.

Listing 18. JSCookMenu tag
<h:form id="dummy2">
 <h:panelGrid columns="2">
  <t:jscookMenu layout="hbr" theme="ThemeOffice">
   <t:navigationMenuItem id="nav_1" itemLabel="#{messages['nav_back_to_flights']}" 
     action="back_to_flights" />
    <t:navigationMenuItem id="nav_2" itemLabel="#{messages['nav_other_choices']}">
    <t:navigationMenuItem id="nav_2_1" itemLabel="#{messages['nav_register_user']}" 
     action="register_new_user" />
    <t:navigationMenuItem id="nav_2_2" itemLabel="#{messages['nav_logout']}" 
    action="logout" split="true" />
   </t:navigationMenuItem>
  </t:jscookMenu>
 </h:panelGrid>
</h:form>

The layout attribute of jscookMenu is set to hbr, which means the menu is laid out horizontally and the children fall to the bottom and right. Other values are hbl (horizontal, bottom, left), hur (horizontal, upper, right), hul (horizontal, upper, left), vbr (vertical, bottom, right), vbl (vertical, bottom, left), vur (vertical, upper, right), and vul (vertical, upper, left). The theme attribute specifies the look and feel of the component using CSS. Figure 10 shows how JSCookMenu looks on the page if the theme is switched to ThemeMiniBlack.

Figure 10. JSCookMenu with ThemeMiniBlack
ThemeMiniBlack

The View — Facelets and XHTML

So far, you've learned about the architecture of the application, the Model, the Controller, and the MyFaces components. Also, since JSF components are exposed as tag libraries, we've looked at some of the source for the XHTML pages. Now it's time to explore how Facelets is used and why it makes things easier in JSF application development.

I mentioned earlier that I changed this application from one that used strictly servlets and JSPs to MyFaces and Facelets. First I migrated my non-JSF JSPs to JSF-based JSPs, then learned about Facelets and changed them from JSPs to XHTML files. It took very little effort, because Facelets supports all of the JSF UIComponents in the same way the JSP tags do. I really only had to change a few lines in my JSP pages, but was able to create a template that allowed me to modularize the pages more than I could with JSP.

Configuring a JSF application for Facelets

Because the default view handler for JSF is JSP, a change needs to be made in the faces-config.xml file, shown in Listing 19. The <view-handler> tag specifies the FaceletsViewHandler class be used for the view. This class is found in the jsf-facelets.jar file you downloaded and copied to the Tomcat webapps/Derby_MyFaces/WEB-INF/lib directory earlier.

Listing 19. Change the faces-config.xml file
<application>
  <!-- Use Facelets instead of JSP-->
  <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>

In addition to the faces-config.xml file needing another entry, the web.xml file for the application needs some additions. To change the suffix of the page type used for the view from JSP to XHTML, you need to add the javax.faces.DEFAULT_SUFFIX parameter. Another required parameter to use tag libraries with Facelets is the facelets.LIBRARIES parameter. The tag library used for the MyFaces Tomahawk components with Facelets is called tomahawk.taglib.xml, which contains the mappings for the additional Tomahawk components. The tag name is mapped to the Java class that implements the component as well as the rendered class if it's a visible component. The last parameter, facelets.DEVELOPMENT, is not required, but allows you to use the error-handling facility of Facelets. Listing 20 shows these parameters and values in the web.xml file.

Listing 20. Additional entries to the web.xml file for use with Facelets and Tomahawk
<context-param>
  <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
  <param-value>.xhtml</param-value>
</context-param>

<context-param>
  <param-name>facelets.LIBRARIES</param-name>
  <param-value>/WEB-INF/tomahawk.taglib.xml</param-value>
</context-param>

<context-param>
  <param-name>facelets.DEVELOPMENT</param-name>
  <param-value>true</param-value>
</context-param>

See the Resources section for a reference to a MyFaces wiki entry with details about enabling a Tomahawk application to use Facelets if you'd like to learn more details about this.

Now that you're set up to use Facelets, look at some of the XHTML pages and the template created to use with them.

XHTML and Facelets templating

Listing 21 shows the first few lines of all the XHTML files in the application. The namespaces referenced are for the JSF HTML and core tags, the Tomahawk tags, and the Facelets tags. Although the HTML and core tags reference a Sun namespace, the MyFaces libraries are used, so these are actually implemented by Apache.

Listing 21. XHTML DOCTYPE and XML namespaces
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
   http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <t:document 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:t="http://myfaces.apache.org/tomahawk">
 ...
</t:document>

I used Facelet's templating abilities to remove some of the redundant text in my JSPs in the title, header, and footer areas, while allowing for different content in the body of the page. To use templates in Facelets, you first need to create a page that serves as the structure for the content of the pages in the application. The idea is to divide the template page into the standard sections for a Web page, such as title, header, body, and footer, and provide default content for each of these sections, leaving room for the ability to override this content.

Listing 22 is a streamlined version (the namespace declarations and a JavaScript function have been removed) of template.xhtml.

Listing 22. The template file for the application
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...
<t:documentHead>
  <link rel="stylesheet" type="text/css" href="../css/basic.css" />
  <title>
   The Apache Derby and MyFaces Flight Reservation Demo
  </title>
</t:documentHead>

<t:documentBody>

  <div id="header">
   <ui:insert name="page_title">
    <ui:include src="pageTitle.xhtml" />
   </ui:insert>
  </div>

<div id="body">
  <br />
   <ui:insert name="body">
   </ui:insert>
  <br />
</div>


<div id="footer">
  <ui:insert name="footer">
   <div class="pageFooter">
    <script type="text/javascript">
document.write
("<a href='" + getSourceUrl() + "#{mypage}.txt'>Show Source</a>");
    </script>
   </div>
  </ui:insert>
</div>

</t:documentBody>
</html>

This template page uses the insert and the include tags from the Facelets library, associated with the ui namespace. The insert tag allows content to be injected in the area on the page that's referenced by the insert's name attribute. For example, a page that wants to use this template file needs to use the define tag, specifying for its name attribute the same name value referenced in the insert tag. In a moment, you'll see an example of a page that uses the define tag to clarify how this works.

Look at the div tag whose id is header in Listing 22. An insert and include tag are nested in this tag. The insert tag has a page_title name, and the include tag points to a src of pageTitle.xhtml. This means the div with the id of header includes the contents of the pageTitle.xhtml page, which is simply the text The Apache Derby and MyFaces Flight Reservation Demo, while allowing it to be superseded by some other content.

It's time to look at Register.xhtml, a page that references and makes use of the template page template.xhtml and introduces the define and composition tags (see Listing 23).

Listing 23. Register.xhtml, using the composition, define, and param tags
...
 <ui:composition template="../format/template.xhtml">
  <ui:define name="page_title">
   <div class="pageHeader">
    Register to use the Apache Derby and MyFaces Flight Reservation Demo
   </div>
   </ui:define>

  <ui:define name="body">
   <f:view>

   ...

   </f:view>
  </ui:define>

  <ui:param name="mypage" value="Register.jsf" />
 </ui:composition>
</t:document>

The composition tag shown in Listing 23 has a template attribute that points to the template page shown in Listing 22. Also, look at the use of the ui:define tag in two places. The first one, with the name of page_title, allows you to override the value for the header of the page. In Listing 22, the page header was The Apache Derby and MyFaces Flight Reservation Demo. Here I've changed it to Register to use the Apache Derby and MyFaces Flight Reservation Demo. The second ui:define tag lets you specify the body of the page, which in the template page has no default content. This means any page that references template.xhtml in its composition tag will have no output in the body section if the ui:define, whose name is body, is omitted from the page.

The last tag to look at in Listing 23 is the ui:param tag. Both the name and value attributes for this tag are required. In this case, I'm using the param tag to pass the name of the current page to the template page to dynamically output a link for the Show Source functionality at the bottom of each page.

To understand where the parameter is used, look back at the footer div in Listing 22. The small section of JavaScript is used to dynamically write output using the document.write function. A URL is constructed by calling the function getSourceUrl() (not shown), which gets the actual URL of the Web application. The JSF EL expression #{mypage} is used to output the page name passed in via the ui:param tag. A .txt extension is added to it, and the proper formatting of the HTML <a href> tag is created to output the Show Source link.

Facelets error message handling

The last topic of this article is the improved error message handling available in Facelets by adding the facelets.DEVELOPMENT parameter to the web.xml file as you saw in Listing 20. To demonstrate how an error appears in the browser using Facelets, I intentionally changed the property name for the LoginBean from the correct value of username to the incorrect value of usersname in the Welcome.xhtml file. Here's the line of code from Welcome.xhtml, which is now incorrect:

<h:inputText id="username" value="#{loginBean.usersname}" required="true" maxlength="20">

Figure 11 shows the output of calling the first page of the application, Welcome.xhtml, with the error handling enabled. Contrast this with the plain old HTTP Status 500 error and stack trace of Figure 12 with it disabled.

Figure 11. Facelets error message display
Facelets error display
Figure 12. Facelets error message facility disabled
Facelets error display

Although the root cause of the error is reported correctly in the stack trace, it's obvious that the Facelets error reporting is an improvement. Not only does it tell you the cause of the error immediately, it also provides the stack trace, available by expanding the + sign. It also allows you to look at the component tree, the request parameters and attributes, and the session and application attributes. Finally, notice how the page starts to render -- you can see the header and the beginning text where there is no error. This helps you visually determine where on the page the problem lies as an additional source of information.


Summary

This article has demonstrated how to develop a JSF Web application using Apache MyFaces, Apache Derby, and Facelets. Some of the Derby functionality explored was using an EmbeddedDataSource, starting and stopping Derby via a ServletContextListener, and using JDBC Prepared and Callable Statements.

The use of Apache MyFaces Tomahawk validators and components were demonstrated along with the visual output to the browser. You examined the navigation of the Web application, as mapped out in the JSF configuration file, faces-config.xml. And you examined a few of the many capabilities of Facelets, such as templating and error handling, and how to configure a Tomahawk-based JSF application to use Facelets.

The ease of development, embeddable nature, and zero-admin characteristics of Apache Derby; the power and breadth of the MyFaces components; and the ease of use and reusability of Facelets build a powerful trio for developing robust and dynamic JSF-based Web applications.


Download

DescriptionNameSize
Source and binary files for the ApplicationApache_Derby_MyFaces_Demo.zip5377KB

Resources

Learn

  • Visit the Apache Derby Web site to access numerous articles about application development using Derby. Version 10.1.3.1 is used in the sample application in this article, and the 10.2 version has just been released and is available for download.
  • Check out the Derby wiki, a great source of information for those new to Derby or for developers and users interested in getting involved in the community.
  • Read the JSF for nonbelievers article series by Rick Hightower on developerWorks to learn more about JSF.
  • Get more information about version 1.1.4 of the MyFaces Core and version 1.1.3 of the Tomahawk components used in the sample Web application. Like the Derby wiki, the MyFaces wiki is for the novice and experienced user.
  • The wiki entry Use Facelets with Tomahawk explains in detail the requirements for using Facelets with the Tomahawk components.
  • Learn more about the advanced capabilities of Facelets.
  • See a definition of the Facelets Framework, how to set up the environment, and information about the API.
  • Refer to "Build Web applications with Eclipse, WTP, and Derby" (developerWorks, September 2005) to compare the application referred to in this article -- built with JSF and Facelets -- with one using servlets and JSPs.
  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
  • Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
  • Browse for books on these and other technical topics at the Safari bookstore.
  • Check out the developerWorks Apache Derby project area for articles, tutorials, and other resources to help you get started with Derby today.
  • Learn more about the IBM® Cloudscape™ database, which is built using the Apache Derby code base.

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Information Management
ArticleID=169241
ArticleTitle=Develop an application with Apache Derby, Apache MyFaces, and Facelets
publish-date=10242006