A look at the Composite design pattern

Treat primitive and composite objects the same way

1 2 3 Page 2
Page 2 of 3

Example 2. A complex layout implemented with JSP includes

<%@ page contentType='text/html; charset=UTF-8' %>
<html>
   <head>
      <title>Implementing Complex Layouts by Hand</title>
   </head>
   <body background='graphics/blueAndWhiteBackground.gif'>
      <%-- One table lays out all of the content for this page --%>
      <table width='100%' height='100%'>
         <tr>
            <%-- Sidebar section --%>
            <td width='150' valign='top' align='left'>
               <jsp:include page='sidebar.jsp'/>
            </td>
            <%-- Main content section --%>
            <td height='100%' width='*'>
               <table width='100%' height='100%'>
                  <tr>
                     <%-- Header section --%>
                     <td valign='top' height='15%'>
                        <jsp:include page='header.jsp'/>
                     </td>
                  <tr>
                  <tr>
                     <%-- Content section --%>
                     <td valign='top' height='*'>
                        <jsp:include page='content.jsp'/>
                     </td>
                  </tr>
                  <tr>
                     <%-- Footer section --%>
                     <td valign='bottom' height='15%'>
                        <jsp:include page='footer.jsp'/>
                     </td>
                  </tr>
               </table>
            </td>
         </tr>
      </table>
   </body>
</html>

The preceding JSP includes the content of other JSPs with <jsp:include>. Because I've encapsulated that content in separate JSPs, you can reuse it for other Webpages:

Example 3. sidebar.jsp

<%@ page contentType='text/html; charset=UTF-8' %>
<table width='100%'>
   <tr>
      <%-- Sidebar top component --%>
      <td width='150' height='65' valign='top' align='left'>
        <a href=''><img src='graphics/flags/britain_flag.gif'/></a>
        <a href=''><img src='graphics/flags/german_flag.gif'/></a>
        <a href=''><img src='graphics/flags/chinese_flag.gif'/></a>
      </td>
   </tr>
   <tr>
      <%-- Sidebar bottom component --%>
      <td>
         <table>
            <tr>
               <td>
                  <font size='5'>Links</font><p>
                  <a href=''>Home</a><br>
                  <a href=''>Products</a><br>
                  <a href=''>Downloads</a><br>
                  <a href=''>White papers</a><br>
                  <a href=''>Contact us</a><br>
               </td>
            </tr>
         </table>
      </td>
   </tr>
</table>

For completeness, I've listed below the JSPs included by the preceding JSP:

Example 4. header.jsp

<font size='6'>Welcome to Sabreware, Inc.</font>
<hr>

Example 5. content.jsp

<font size='4'>Page-specific content goes here</font>

Example 6. footer.jsp

<hr>
Thanks for stopping by!

Even though Example 2's JSP uses <jsp:include> to reuse content, you can't reuse the page's layout because it's hardcoded in that JSP. Struts Tiles lets you reuse both the content and the layout, as illustrated in the next section.

Implement complex layouts with Struts Tiles

Example 7 shows the Webpage in Figure 3 implemented with Struts Tiles:

Example 7. Use Struts Tiles to encapsulate layout

<%@ page contentType='text/html; charset=UTF-8' %>
<%@ taglib uri='WEB-INF/tlds/struts-tiles.tld' prefix='tiles' %>
<tiles:insert definition='sidebar-header-footer-definition'/>

The preceding JSP uses the <tiles:insert> tag to create Figure 3's JSP. That JSP is defined by a tiles definition named sidebar-header-footer-definition. That definition resides in the Tiles configuration file, which in this case is WEB-INF/tiles-defs.xml, listed in Example 8:

Example 8. WEB-INF/tiles-defs.xml

<!DOCTYPE tiles-definitions PUBLIC
  "-//Apache Software Foundation//DTD Tiles Configuration//EN"
  "http://jakarta.apache.org/struts/dtds/tiles-config.dtd">
<tiles-definitions>
   <definition  name='sidebar-header-footer-definition' 
                path='header-footer-sidebar-layout.jsp'>
      <put name='sidebar' value='sidebar.jsp'/>
      <put name='header'  value='header.jsp'/>   
      <put name='content' value='content.jsp'/>   
      <put name='footer'  value='footer.jsp'/>   
   </definition>
</tiles-definitions>

The preceding Tiles definition specifies the page layout, encapsulated in header-footer-sidebar-layout.jsp, and the page's content, encapsulated in sidebar.jsp, header.jsp, content.jsp, and footer.jsp, as listed in Examples 3-6. Example 9 lists the JSP that defines the layout—header-footer-sidebar-layout.jsp:

Example 9. header-footer-sidebar-layout.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ page contentType='text/html; charset=UTF-8' %>
<html>
   <head>
      <title>Struts Tiles implements the Composite pattern</title>
   </head>
   <body background='graphics/blueAndWhiteBackground.gif'>
      <%@ taglib uri='/WEB-INF/tlds/struts-tiles.tld' 
              prefix='tiles'%>
      <%-- One table lays out all of the content --%>
      <table width='100%' height='100%'>
         <%-- Sidebar section --%>
         <tr>
            <td width='150' valign='top' align='left'>
               <tiles:insert attribute='sidebar'/>
            </td>
            <%-- Main content section --%>
            <td valign='top' height='100%' width='*'>
               <table width='100%' height='100%'>
                  <tr>
                     <%-- Header section --%>
                     <td height='15%'>
                        <tiles:insert attribute='header'/>
                     </td>
                  <tr>
                  <tr>
                     <%-- Content section --%>
                     <td valign='top' height='*'>
                        <tiles:insert attribute='content'/>
                     </td>
                  </tr>
                  <tr>
                     <%-- Footer section --%>
                     <td valign='bottom' height='15%'>
                        <tiles:insert attribute='footer'/>
                     </td>
                  </tr>
               </table>
            </td>
         </tr>
      </table>
   </body>
</html>

The preceding JSP encapsulates layout and inserts content according to the values specified for the sidebar, editor, content, and footer regions in the Tiles definition file, thus easing reuse for both the content and the layout. For example, you could define another Tiles definition with the same layout, the same sidebar, editor, and footer, but different content:

<tiles-definitions>
   <definition  name='a-different-sidebar-header-footer-definition' 
                path='header-footer-sidebar-layout.jsp'>
      <put name='sidebar' value='sidebar.jsp'/>
      <put name='header'  value='header.jsp'/>   
      <put name='content' value='someOtherContent.jsp'/>   
      <put name='footer'  value='footer.jsp'/>   
   </definition>
</tiles-definitions>

To create the JSP defined by the tiles definition a-different-sidebar-header-footer-definition, you use the <tiles:insert> tag, like this:

<%@ page contentType='text/html; charset=UTF-8' %>
<%@ taglib uri='WEB-INF/tlds/struts-tiles.tld' prefix='tiles' %>
<tiles:insert definition='a-different-sidebar-header-footer-definition'/>

Thanks to Struts Tiles, you can reuse both content and layout, which proves invaluable for Websites with many JSPs that share layout and some content. But if you look closely at the code from Examples 7-9, you will notice that the layout for the sidebar region is hardcoded in sidebar.jsp, which is listed in Example 3. That means you cannot reuse that layout. Fortunately, the Tiles tag library implements the Composite pattern, which lets us specify a tiles definition—instead of a JSP—for a region. In the next section, I explain how to use that Composite pattern implementation.

Use the Composite pattern with Struts Tiles

Struts Tiles implements the Composite pattern, where the Component class is represented by JSPs and the Composite class is represented by a Tiles definition. That implementation lets you specify either a JSP (a component) or a Tiles definition (a composite) as the content for a JSP's region. Example 10 illustrates that feature:

Example 10. WEB-INF/tiles-defs.xml: Use the Composite pattern

<!DOCTYPE tiles-definitions PUBLIC
  "-//Apache Software Foundation//DTD Tiles Configuration//EN"
  "http://jakarta.apache.org/struts/dtds/tiles-config.dtd">
<tiles-definitions>
   <definition  name='sidebar-definition' 
                path='sidebar-layout.jsp'>
      <put name='top'    value='flags.jsp'/>
      <put name='bottom' value='sidebar-links.jsp'/>
   </definition>
   <definition  name='sidebar-header-footer-definition' 
                path='header-footer-sidebar-layout.jsp'>
      <put name='sidebar' value='sidebar-definition'
           type='definition'/>
      <put name='header'  value='header.jsp'/>
      <put name='content' value='content.jsp'/>
      <put name='footer'  value='footer.jsp'/>
   </definition>
</tiles-definitions>

The preceding Tiles configuration file defines two Tiles definitions: sidebar-definition and sidebar-header-footer-definition. The sidebar-definition is specified as the value for the sidebar region in the sidebar-header-footer-definition. You can specify it as such because Tiles implements the Composite pattern by letting Tiles specify a definition (a Composite that's a JSP collection) where you would normally specify a single JSP (which is a Component).

The sidebar's layout is encapsulated in Example 11's sidebar-layout.jsp:

Example 11. sidebar-layout.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ page contentType='text/html; charset=UTF-8' %>
<%@ taglib uri='/WEB-INF/tlds/struts-tiles.tld' prefix='tiles'%>
<table width='100%'>
   <tr>
      <td width='150' height='65' valign='top' align='left'>
         <tiles:insert attribute='top'/>
      </td>
   </tr>
   <tr>
      <td>
         <table>
            <tr>
               <td><tiles:insert attribute='bottom'/></td>
            </tr>
         </table>
      </td>
   </tr>
</table>

Example 12 lists flags.jsp, specified as the content for the sidebar's top region, and Example 13 lists sidebar-links.jsp, specified as the sidebar's bottom region:

Example 12. flags.jsp

<table>
   <tr><td>
      <a href=''><img src='graphics/flags/britain_flag.gif'/></a>
      <a href=''><img src='graphics/flags/german_flag.gif'/></a>
      <a href=''><img src='graphics/flags/chinese_flag.gif'/></a>
   </td></tr>
</table>

Example 13. sidebar-links.jsp

<p>
<font size='5'>Links</font><p>
<a href=''>Home</a><br>
<a href=''>Products</a><br>
<a href=''>Downloads</a><br>
<a href=''>White papers</a><br>
<a href=''>Contact us</a><br>

Now the sidebar-definition can define other regions with a top and bottom component, although you should probably rename that definition to something more generic like top-bottom-definition.

It's all composites these days

The Composite pattern is popular with presentation frameworks, such as Swing and Struts, because it lets you nest containers by treating components and their containers exactly the same. Struts Tiles uses the Composite pattern to specify a simple JSP or a Tiles definition—which is a collection of JSPs—as a tile's content. That's a powerful capability that eases management of large Websites with different layouts.

The "Homework from Last Time" section below expands on this article's discussion by internationalizing the preceding application with a Struts action and the JSP Standard Tag Library (JSTL).

Homework

Discuss how Swing implements the composite pattern with the Component and Container classes.

Homework from last time

Your last assignment asked you to download Struts from http://jakarta.apache.org/struts/index.html and implement your own Struts action class.

For this assignment, I decided to implement a Struts action in conjunction with the JSP Standard Tag Library (JSTL) to internationalize Example 1's Web application. Although Struts provides the necessary infrastructure to internationalize your Web applications, you should use JSTL for that task, because JSTL is a standard. At some point, the Struts internationalization capabilities will probably be deprecated or integrated with JSTL.

After I internationalized Example 1's Web application with a Struts action and JSTL, I localized that application for Chinese. Figure H1 illustrates the result.

Note: I don't know a single word of Chinese, let alone how to write the language, so Figure H1's Chinese is fabricated from arbitrary Unicode strings. But it looks cool, regardless.

Figure H1. Internationalization with a Struts Action. Click on thumbnail to view full-size image.

Notice I specified the href attributes in Example 12's flags.jsp as empty strings, so when you click on the flags, the servlet container reloads the current JSP. Therefore, the first step towards internationalizing the Web application is to specify a URL for those attributes, as listed in Example H1:

Example H1. flags.jsp

<table>
   <tr><td>
      <a href='flags.do?locale=en-GB&fwdPage=<%=request.getServletPath()%>'>
         <img src='graphics/flags/britain_flag.gif'/></a>
      <a href='flags.do?locale=de-DE&fwdPage=<%=request.getServletPath()%>'>
         <img src='graphics/flags/german_flag.gif'/></a>
      <a href='flags.do?locale=zh-ZH&fwdPage=<%=request.getServletPath()%>'>
         <img src='graphics/flags/chinese_flag.gif'/></a>
   </td></tr>
</table>

1 2 3 Page 2
Page 2 of 3