The Library

Content Inclusion in the Book Viewer

To include content in the book viewer, we split our monolithic JSF page into four files: the original JSF page, /header.jsp, /menu.jsp, and /content.jsp. We include the header, menu, and content in the original JSF page:

  <h:panelGrid columns="2" style      columnClasses="menuColumn, contentColumn">      <f:facet name="header">         <f:subview >            <c:import url="header.jsp"/>         </f:subview>      </f:facet>      <f:subview >         <c:import url="menu.jsp"/>      </f:subview>       <c:import url="content.jsp"/>   </h:panelGrid>   ...

This code is much cleaner than the original JSF page listed in Listing 8-1, so it is easier to understand, maintain, and modify. But more important, we are now free to reuse the header, menu, and content for other views.

The directory structure for the book viewer with includes example is shown in Figure 8-5. Listing 8-6 through Listing 8-9 show the JSF pages for the book, its header, menu, and content.

Figure 8-5. The directory structure of the book viewer with includes


Listing 8-6. book-viewer-include/web/book.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/core"  prefix="f" %>   4.    <%@ taglib uri="http://java.sun.com/jsf/html"  prefix="h" %>   5.   6.    <f:view>   7.       <f:loadBundle basename="com.corejsf.messages" var="msgs"/>   8.       <head>   9.          <link href="styles.css" rel="stylesheet" type="text/css"/>  10.          <title><h:outputText value="#{msgs.bookWindowTitle}"/></title>  11.       </head>  12.  13.       <body>  14.          <h:form>  15.             <h:panelGrid columns="2" style  16.                    columnClasses="menuColumn, chapterColumn">  17.                <f:facet name="header">  18.                   <f:subview >  19.                      <c:import url="/bookHeader.jsp"/>  20.                   </f:subview>  21.                </f:facet>  22.  23.                <f:subview >  24.                   <c:import url="/bookMenu.jsp"/>  25.                </f:subview>  26.  27.                <c:import url="/bookContent.jsp"/>  28.             </h:panelGrid>  29.          </h:form>  30.       </body>  31.    </f:view>  32. </html>     

Listing 8-7. book-viewer-include/web/bookHeader.jsp

  1. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   2. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   3.   4. <h:panelGrid columns="1" style>   5.    <h:graphicImage value="#{book.image}"/>   6.    <h:outputText value="#{msgs[book.titleKey]}" style/>   7.    <hr>   8. </h:panelGrid>     

Listing 8-8. book-viewer-include/web/bookMenu.jsp

  1. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   2. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   3.   4. <h:dataTable value="#{book.chapterKeys}" var="chapterKey"   5.         style columnClasses="linksColumn">   6.    <h:column>   7.       <h:commandLink>   8.          <h:outputText value="#{msgs[chapterKey]}"/>   9.          <f:param name="chapter" value="#{chapterKey}"/>  10.       </h:commandLink>  11.    </h:column>  12. </h:dataTable>

Listing 8-9. book-viewer-include/web/bookContent.jsp

  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   2.   3. <c:import url="${param.chapter}.html"/>

Looking at Tiles

We have seen how to encapsulate and include content and how that strategy increases flexibility it is much easier to reuse content if you include it rather than mixing it all in one file. Now that you can create user interfaces with pluggable content, you may be satisfied with that level of flexibility and reuse but wait, there's more.

In addition to encapsulating content, you can use Tiles to encapsulate layout. For the application shown in Figure 8-2 on page 317, encapsulating layout means making the layout code the h:panelGrid and its contents listed in Listing 8-6 on page 330 available for reuse. As it stands in Listing 8-6, that layout code can only be used by the JSF page shown in Figure 8-2. If you implement JSF pages with identical layouts, you must replicate that layout code for every page.

With Tiles, you define a single layout that can be reused by multiple tiles, which are nothing more mysterious than imported JSP pages. Tiles lets you implement layout code once and reuse it among many pages.

But reusing layout is just the beginning of the Tiles bag of tricks. You can do more:

  • Nest tiles

  • Extend tiles

  • Restrict tiles to users of a particular role

  • Attach controllers (Java objects) to tiles that are invoked just before their tile is displayed

Those are the core features that Tiles offers in the pursuit of the ultimate flexibility in crafting web-based user interfaces.

Installing Tiles

To use Tiles, you need the standalone Tiles JAR file. That JAR file can be found in the source code for this book.

Once you have the Tiles JAR file, follow these steps to install Tiles in your application:

  1. Copy the Tiles JAR file to your application's WEB-INF/lib directory.

  2. Add the Tiles servlet to your deployment descriptor (web.xml). Use the load-on-startup element to ensure that the Tiles servlet is loaded when your application starts.

Your deployment descriptor should look similar to the following:

  <?xml version="1.0"?>   <web-app xmlns="http://java.sun.com/xml/ns/j2ee"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee              http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"           version="2.4">      ...      <servlet>         <servlet-name>Faces Servlet</servlet-name>         <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>         <load-on-startup>1</load-on-startup>      </servlet>      <servlet>         <servlet-name>Tiles Servlet</servlet-name>         <servlet-class>org.apache.tiles.servlets.TilesServlet</servlet-class>          <load-on-startup>2</load-on-startup>      </servlet>      ...   </web-app>     

Using Tiles with the Book Viewer

Using Tiles with JSF is a three-step process:

  1. Use tiles:insert to insert a tile definition in a JSF page.

  2. Define the tile in your Tiles configuration file.

  3. Implement the tile's layout.

For the book viewer, we start in book.jsp, where we insert a tile named book:

  ...   <%@ taglib uri="http://jakarta.apache.org/tiles" prefix="tiles" %>   ...   <h:form>      <tiles:insert definition="book" flush="false"/>   </h:form>   ...

We define the book tile in /WEB-INF/tiles.xml:

  <definition name="book" path="/headerMenuContentLayout.jsp">       <put name="header" value="/bookHeader.jsp"/>       <put name="menu" value="/bookMenu.jsp"/>       <put name="content" value="/bookContent.jsp"/>   </definition>

The previous snippet of XML defines a tile. The tile's layout is specified with the definition element's path attribute. The tile attributes, specified with put elements, are used by the layout. That layout looks like this:

  <%-- this is /headerMenuContentLayout.jsp --%>   <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>   <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>   <%@ taglib uri="http://jakarta.apache.org/tiles" prefix="tiles" %>   <h:panelGrid columns="2" styleClass="gridClass"      headerClass="headerClass"      columnClasses="menuClass, contentClass">      <f:facet name="header">         <f:subview >            <tiles:insert attribute="header" flush="false"/>         </f:subview>      </f:facet>      <f:subview >         <tiles:insert attribute="menu" flush="false"/>      </f:subview>      <f:subview >         <tiles:insert attribute="content" flush="false"/>      </f:subview>   </h:panelGrid>

The tiles:insert tag dynamically includes content. That content is the value of the attribute tag of tiles:insert. For example, the preceding code inserts the header attribute. That attribute's value is /bookHeader.jsp, so tiles:insert dynamically includes that file.

Notice that we specified a flush="false" attribute for the tiles:insert tag. That is necessary for most modern servlet containers because those containers disallow buffer flushing inside custom tags. If your servlet container throws an exception stating that you cannot flush from a custom tag, then you know you have forgotten to specify that attribute, which is true by default.

What have we gained by using Tiles in this example? We have encapsulated layout so that we can reuse it in other tiles, instead of replicating that layout code from one JSF page to another. For example, you could reuse the book viewer's layout, implemented in /headerMenuContentLayout.jsp, for other pages in the application that have the same layout.

Parameterizing Tiles

There is one flaw to the layout listed in the previous section: It hardcodes CSS classes, namely gridClass, headerClass, menuClass, and contentClass. This means that every web page using the header-menu-content layout will have the same look and feel. It would be better if we could parameterize the CSS class names. That way, other tiles with a header-menu-content layout could define their own look and feel.

Next, we look at how we can do that. First, we add three attributes to the book tile:

  <definition name="book" path="/headerMenuContentLayout.jsp">      <put name="headerClass"  value="headerClass"/>      <put name="menuClass" value="menuClass"/>      <put name="contentClass" value="contentClass"/>      <put name="header" value="/bookHeader.jsp"/>      <put name="menu" value="/bookMenu.jsp"/>      <put name="content" value="/bookContent.jsp"/>   </definition>

Then we use those attributes in the layout:

  <%-- this is an excerpt of /headerMenuContentLayout.jsp --%>   ...   <tiles:importAttribute scope="request"/>   <h:panelGrid columns="2" style      header      columnClasses="#{menuClass}, #{contentClass}">      ...   </h:panelGrid>

Tile attributes, such as headerClass, menuClass, etc., in the preceding code, exist in tiles scope, which is inaccessible to JSF. To make our attributes accessible to the layout JSF page listed above, we use the tiles:importAttribute tag. That tag imports all tile attributes to the scope you specify with the scope attribute. In the preceding code, we imported them to request scope.

Now we can specify different CSS classes for other tiles:

  <definition name="anotherTile" path="/headerMenuContentLayout.jsp">      <put name="headerClass" value="aDifferentHeaderClass"/>       ...   </definition>

Note

The tiles:importAttribute tag also lets you import one attribute at a time for example: <tiles:importAttribute name="headerClass" scope="..."/>.


Extending Tiles

In "Parameterizing Tiles" on page 334 we defined a tile that looked like this:

  <definition name="book" path="/headerMenuContentLayout.jsp">      <put name="headerClass"  value="headerClass"/>      <put name="menuClass" value="menuClass"/>      <put name="contentClass" value="contentClass"/>      <put name="header" value="/bookHeader.jsp"/>      <put name="menu" value="/bookMenu.jsp"/>      <put name="content" value="/bookContent.jsp"/>   </definition>

There are two distinct types of attributes in that tile: CSS classes and included content. Although the latter is specific to the book tile, the former can be used by tiles that represent something other than books. Because of that generality, we split the book tile into two:

  <definition name="header-menu-content" path="/headerMenuContentLayout.jsp">      <put name="headerClass" value="headerClass"/>      <put name="menuClass" value="menuClass"/>      <put name="contentClass" value="contentClass"/>   </definition   <definition name="book" extends="header-menu-content">      <put name="header" value="/bookHeader.jsp"/>      <put name="menu" value="/bookMenu.jsp"/>      <put name="content" value="/bookContent.jsp"/>   </definition>     

Now the book tile extends the header-menu-content tile. When you extend a tile, you inherit its layout and attributes, much the same as Java subclasses inherit methods and variables from their base classes. Because we have split the original tile in two, the CSS class attributes are available for reuse by other tiles that extend the header-menu-content tile.

Note

Here is one more thing to consider about Tiles. Imagine the book viewer has been a huge success and Project Gutenberg has commissioned you to implement a library that can display all 6,000+ of their books. You define more than 6,000 tiles that reuse the same layout one tile for each book and present your finished product to the folks at Gutenberg. They think it's great, but they want you to add a footer to the bottom of every page. Since you have used Tiles, you only need to change the single layout used by all your tiles. Imagine the difficulty you would encounter making that change if you had replicated the layout code more than 6,000 times!


Figure 8-6 shows the directory structure for the "tileized" version of the book viewer. That directory structure is the same as the previous version of the book viewer, except that we have added a layout headerMenuContentLayout.jsp and the tiles definition file, /WEB-INF/tiles.xml.

Figure 8-6. Book viewer with extended tile directory structure


Listing 8-10 through Listing 8-12 show the Tiles definition file, the book layout, and the JSF page that displays Alice in Wonderland. We left out the listings of the other files in the application because they are unchanged from the application discussed in "Content Inclusion in JSP-Based Applications" on page 326.

Listing 8-10. book-viewer-tiles/web/WEB-INF/tiles.xml

  1. <!DOCTYPE tiles-definitions PUBLIC   2.    "-//Apache Software Foundation//DTD Tiles Configuration//EN"   3.    "http://jakarta.apache.org/struts/dtds/tiles-config.dtd">   4.   5. <tiles-definitions>   6.    <definition name="book" path="/headerMenuContentLayout.jsp">   7.        <put name="gridClass"           value="headerMenuContent"/>   8.        <put name="headerClass"         value="header"/>   9.        <put name="menuColumnClass"     value="menuColumn"/>  10.        <put name="contentColumnClass"  value="contentColumn"/>  11.  12.       <put name="header"  value="/bookHeader.jsp"/>  13.       <put name="menu"    value="/bookMenu.jsp"/>  14.       <put name="content" value="/bookContent.jsp"/>  15.    </definition>  16. </tiles-definitions>

Listing 8-11. book-viewer-tiles/web/headerMenuContentLayout.jsp

  1. <%@ taglib uri="http://java.sun.com/jsf/core"  prefix="f" %>   2. <%@ taglib uri="http://java.sun.com/jsf/html"  prefix="h" %>   3. <%@ taglib uri="http://jakarta.apache.org/tiles" prefix="tiles" %>   4.   5. <tiles:importAttribute scope="request"/>   6.   7. <h:panelGrid columns="2" style   8.       header   9.       columnClasses="#{menuColumnClass}, #{contentColumnClass}">  10.    <f:facet name="header">  11.       <f:subview >  12.         <tiles:insert attribute="header" flush="false"/>  13.       </f:subview>  14.    </f:facet>  15.  16.    <f:subview >  17.       <tiles:insert attribute="menu" flush="false"/>  18.    </f:subview>  19.  20.    <f:subview >  21.       <tiles:insert attribute="content" flush="false"/>  22.    </f:subview>  23. </h:panelGrid>     

Listing 8-12. book-viewer-tiles/web/book.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/core"  prefix="f" %>   4.    <%@ taglib uri="http://java.sun.com/jsf/html"  prefix="h" %>   5.    <%@ taglib uri="http://jakarta.apache.org/tiles" prefix="tiles" %>   6.   7.    <f:view>   8.       <f:loadBundle basename="com.corejsf.messages" var="msgs"/>   9.       <head>  10.          <link href="styles.css" rel="stylesheet" type="text/css"/>  11.          <title><h:outputText value="#{msgs.bookWindowTitle}"/></title>  12.       </head>  13.  14.       <body>  15.          <f:subview >  16.             <h:form>  17.                <tiles:insert definition="book" flush="false"/>  18.             </h:form>  19.          </f:subview>  20.       </body>  21.    </f:view>  22. </html>     



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net