Web application components made easy with Composite View

Implement Web applications featuring pluggable components with the Composite View design pattern

In Core J2EE Patterns: Best Practices and Design Strategies, Deepak Alur, John Crupi, and Dan Malks identify 15 J2EE (Java 2 Platform, Enterprise Edition) design patterns, of which the Composite View pattern proves to be one of the most compelling. The Composite View pattern builds composite views from multiple subviews, with the potential to greatly simplify application development by allowing content and layout to be plugged into a framework.

Before the Composite View pattern was widely known, developers knew it as JSP (Java Server Pages) templates; a term that originated in Sun's J2EE Blueprints. Templates combine the Composite and Strategy patterns (both espoused by the Gang of Four (GOF) in Design Patterns) to separate both content and layout from JSPs. Such separation defines a JSP programming style that lets page authors and software developers work, for the most part, independently.

The templates description in J2EE Blueprints motivated me to write a templates custom tag library, which I contributed to the Apache Struts project in fall 2000. Not long after that, I wrote about that tag library for JavaWorld in "JSP Templates" (September 2000). Consequently, feedback from both JavaWorld readers and Struts users prompted me to rewrite the templates tag library from scratch for my book Advanced JavaServer Pages.

In spring 2001, I contributed some code from the rewritten templates tag library -- now known as the regions tag library -- to illustrate the Composite View J2EE design pattern in the aforementioned Core J2EE Patterns: Best Practices and Design Strategies.

This article discusses the Composite View pattern by exploring the regions tag library in more detail. Also, because the tag library examined in this article is a second revision of the library discussed in JavaWorld's "JSP Templates," you can view this article as somewhat of a sequel.

The Composite View pattern

Nearly all modern object-oriented development environments support three key objects for flexible and extensible graphical user interface (GUI) development: components, containers, and layout managers. Components represent graphic objects such as text, buttons, or lists. Containers maintain component lists, while layout managers position and size (or lay out) a container's components.

Developers typically implement components and containers with the GOF Composite design pattern, which lets you compose graphical objects into tree hierarchies. Meanwhile, layout managers are typically implemented with the GOF Strategy design pattern, so that you can change a container's layout strategy at runtime without changing the container itself. For its part, the J2EE Composite View design pattern acts as a recipe for components, containers, and layout managers for JSP-based Web applications.

At the low end, the Composite View pattern resembles the GOF Composite pattern. In describing the Composite View pattern in Core J2EE Design Patterns, Alur, Crupi, and Malks write, "Use composite views that are composed of multiple atomic subviews...," which means your views should be composites that can contain other views -- an endorsement of the GOF Composite pattern. Those views can be composites also, so you can arrange views in a tree hierarchy.

At the high end, the Composite View pattern details the steps necessary to implement components, containers, and layout managers. The authors continue:

Each component of the template may be included dynamically into the whole, and the layout of the page may be managed independently of the content.

Thus, the authors recommend pluggable views and layout management. Dynamic content and encapsulated layout go a long way toward simplifying and maintaining JSP-based Web applications. Let's see how.

Note: The complete source code for this article can be downloaded from Resources.

Sections, regions, and templates

Because the Composite View pattern targets Web applications, its components, containers, and layout managers differ from those found in a traditional GUI application. To reflect that difference, in the regions tag library discussed in Advanced JavaServer Pages, I renamed them:

  • Section: (component) An object that renders HTML or a JSP
  • Region: (container) An object that contains sections
  • Template: (layout manager) A JSP that lays out regions and sections

In Figure 1 you'll see a typical login screen for a Web application implemented with the J2EE Composite View pattern.

Figure 1. A typical Webpage login screen implemented with the Composite View pattern

In the Webpage shown in Figure 1, one region, representing the entire page, contains four sections:

  1. Sidebar
  2. Header
  3. Content
  4. Footer

Regions contain sections, but they can also contain other regions, so you can nest regions and sections in a tree hierarchy. The application shown in Figure 1 also employs the Composite View pattern to encapsulate layout, specified in a JSP called a template.

Webpages, like the one shown in Figure 1, comprise two aspects: content and layout. The Composite View pattern makes those aspects pluggable.

Pluggable content

You can easily make content pluggable with either <jsp:include> or <%@ include %>. The former dynamically includes content at runtime, whereas the latter includes content at translation time. The JSP for the application shown in Figure 1 uses <jsp:include> to dynamically include content for each page's region, as seen below:

Example 1. Pluggable content

<html><head>
   <title>Fruitstand.com</title>
</head>
<body background='graphics/blueAndWhiteBackground.gif'>
<table>
   <tr valign='top'><td><jsp:include file='sidebar.jsp'/></td>
      <td><table>
         <tr><td><jsp:include file='header.jsp'/></td></tr>
         <tr><td><jsp:include file='introduction.jsp'/></td></tr>
         <tr><td><jsp:include file='footer.jsp'/></td></tr>
         </table>
      </td>
   </tr> 
</table>
</body>
</html>

Pluggable content is preferable to embedded content for two reasons: First, the content -- in this case sidbar.jsp, header.jsp, and so on -- can vary without modifying the displaying JSP file. Second, the extra level of indirection promotes reuse; for example, the preceding code can display any JSP conforming to the same layout and using the same filenames, such as sidebar.jsp. In contrast, if you embedded the content of sidebar.jsp, header.jsp, introduction.jsp, and footer.jsp in the file, the code would not be reusable.

Pluggable layout

Pluggable content is great, but typically content and layout are tightly coupled because developers specify them in the same file, as is the case for Example 1. With one more level of indirection, you also can make layout pluggable. Let's revisit Example 1 and split it into two JSP files. The first, known as a JSP template, encapsulates layout, as seen in Example 2.a:

Example 2.a. A JSP template

<html><head>
   <%@ taglib uri='regions' prefix='region' %>
   <title>Fruitstand.com</title>
</head>
<body background='graphics/blueAndWhiteBackground.gif'>
<table>
   <tr valign='top'><td><region:render section='sidebar'/></td>
      <td><table>
         <tr><td><region:render section='header'/></td></tr>
         <tr><td><region:render section='content'/></td></tr>
         <tr><td><region:render section='footer'/></td></tr>
         </table>
      </td>
   </tr> 
</table>
</body>
</html>

Notice the similarities between Example 2.a and Example 1. The only difference: the template (Example 2.a) uses a custom tag to include content, whereas Example 1 uses the standard JSP include action. Because the template does not directly refer to the files it includes, any JSP conforming to the sidebar/header/content/footer format can reuse the template.

Templates use only the region:render tag from the regions tag library. That tag extracts the content for each section from a region stored in application scope; for example, in the preceding code, the region:render tag extracts the content for the sidebar section. Section content, always a string, most often represents a file. By default, the region:render tag dynamically includes the file represented by a section's content. In the preceding code, for example, region:render will include the file /sidebar.jsp when it renders the sidebar section.

Other JSP files that directly specify content employ templates; for example, Example 2.b lists a JSP that uses the template listed in Example 2.a:

Example 2.b. Render a region

<%@ taglib uri='regions' prefix='region' %>
<region:render template='/MyTemplate.jsp'>
  <region:put section='header' content='/header.jsp' />
  <region:put section='sidebar'content='/sidebar.jsp' />
  <region:put section='content'content='/introduction.jsp'/>
  <region:put section='footer' content='/footer.jsp' />
</region:render>

Example 2.b's code demonstrates how to use a template. The region:render start tag stores the template name and creates a new region. The region:put tags create new sections in that region. Finally, the region:render end tag dynamically includes the template specified in the region:render start tag. Subsequently, the template renders the aforementioned regions.

So, how do you benefit from this indirection? You can use a single template, which encapsulates layout, for all Webpages with similar formats. As a consequence, you can change the layout for many Webpages simply by modifying a single template. Also, because you reuse the layout for many pages, that layout does not have to be repeated in JSP files that use it.

Direct content

Sometimes you want to render section content directly, rather than treating the content as an included file; for example, the JSP shown in Figure 2 sets the window title to Direct Content.

Figure 2. Direct content

The JSP shown in Figure 2 is listed in Example 3.a:

Example 3.a. Specify direct content

<%@ taglib uri='regions' prefix='region' %>
<table>
   <tr>
      <td>
         <region:render template='template.jsp'>
            <region:put section='title'  
            content='Direct Content' direct='true'/>
            <region:put section='header'  content='/header.jsp'/>
            <region:put section='sidebar' content='/sidebar.jsp'/>
            <region:put section='content' content='/content.jsp'/>
            <region:put section='footer'  content='/footer.jsp'/>
         </region:render>
      </td>
   </tr>
</table>

The JSP in Example 3.a specifies a section for the window title. But unlike the header, sidebar, content, and footer sections, you don't want the template to regard the title section's content as a filename; instead, you want that content to resolve to text. To accomplish that task, you specify true for the direct attribute of the region:put tag.

You don't need to change a template to support direct rendering of a section's content. Example 3.b lists the template used by the JSP listed in Example 3.a:

Example 3.b. Render direct content with a template

<html><head>
  <%@ taglib uri='regions' prefix='region' %>
  <title><region:render section='title'/></title>
</head>
<table border='1' height='250' width='450'>
   <tr> <%-- Sidebar --%>
      <td valign='top' width='25%'>
         <region:render section='sidebar'/>
      </td>
      <td valign='top' align='center' width='*'>
         <table height='250'>
            <tr> <%-- Header --%>
               <td align='center' height='20%'>
                  <region:render section='header'/>
               </td>
            </tr> <%-- Main Content --%>
               <td align='center' height='*'>
                  <region:render section='content'/>
               </td>
            </tr> <%-- Footer --%>
               <td align='center' height='15%'>
                  <region:render section='footer'/>
               </td>
            </tr>
         </table>
      </td>
   </tr>
</table>
</body></html>

The JSP files for the sidebar, header, content, and footer sections are nothing more than simple strings with a specific font. I've listed all four files in Example 3.c:

Example 3.c. Placeholder JSP files

<font size='5'>SIDEBAR</font> <!--sidebar.jsp-->
<font size='5'>HEADER</font>  <!--header.jsp-->
<font size='5'>CONTENT</font> <!--content.jsp-->
<font size='5'>FOOTER</font>  <!--footer.jsp-->

I employ both the template listed in Example 3.b and the placeholder files listed in Example 3.c throughout the remainder of this article.

1 2 3 Page 1
Page 1 of 3