Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Typically during Web application development, the user interface (UI) group creates the site's look and feel. Based on that look and feel, the group creates HTML pages that represent the application's functionality and navigation. With a servlets and JavaServer Pages (JSPs)-based implementation, where HTML pages are converted into servlets and JSPs, UI developers identify common HTML and JSP view components, such as header, footer, body, menu, and search. This article presents various solutions to effectively and efficiently organize HTML and JSP view components. I evaluate each solution using specific criteria, such as page number, code repetition, and layout control.
To explore templating and layout solutions, we will use the Tiles framework. The Tiles framework's view components are known as tiles. The framework uses an XML configuration file to organize those tiles. This framework not only enables you to reuse tiles, but also the layouts that organize them.
To explore the more powerful and flexible solutions, we will investigate the synergy between the Tiles and Struts frameworks. Struts is an open source framework for developing Web applications using the popular Model-View-Controller (MVC) or Model 2 architectural pattern. Struts comes with a large set of reusable tags for which the Tiles tag library makes an excellent enhancement.
I will evaluate each solution based on the criteria below. The criteria are not mutually exclusive. For a specific situation and particular application, you must always balance between the strengths and weaknesses of each solution with respect to these factors.
a.jsp:
<html> <body> Header <p> a's body... <p> Footer <p> </body> </html>
Consider the following JSP for b.jsp:
<html> <body> Header <p> b's body... <p> Footer <p> </body> </html>
In many cases, the developers obtain the code from the UI group and literally convert it into a JSP as necessary. As shown above, each JSP has a duplicate header and footer. Solution 1 is undesirable because changes in common view components, like header and footer, require changes in all relevant pages, as each page is responsible for laying out the view components. This simple solution lacks foresight. With so much HTML and JSP code duplication, we minimize the number of pages but at a heavy maintenance cost. There is strong coupling between the different view components, which, as I explained earlier, is undesirable.
a.jsp:
<html> <body> <%-- include header --%> <jsp:include page="/header.jsp" /> a's body... <p> <%-- include footer --%> <jsp:include page="/footer.jsp" /> </body> </html>
Consider the following JSP for b.jsp:
<html> <body> <%-- include header --%> <jsp:include page="/header.jsp" /> b's body... <p> <%-- include footer --%> <jsp:include page="/footer.jsp" /> </body> </html>
Note that common view components, like header and footer, are split up using the JSP include mechanism.
Consider this header.jsp:
Header <p>
Consider this footer.jsp:
Footer <p>
Solution 2 nicely addresses some of Solution 1's major shortcomings. You only need to change common view components once. Hence, this solution greatly eliminates HTML and JSP code repetition, significantly improving application maintainability. It increases the page number a bit, but drastically reduces the tight coupling between common view components and other pages. On the complexity scale, this solution is simple and readily implemented on many real-world applications. However, it has one major drawback: if you change how and where you organize the view components (i.e., by changing the component layout), then you would need to update every page -- resulting in an expensive and prohibitive change. Solution 2 achieves view component reuse, but does not achieve the reuse of layout and templating logic.
Consider this JSP for a.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %> <html> <body> <%-- include header --%> <tiles:insert page="/header.jsp" flush="true"/> a's body... <p> <%-- include footer --%> <tiles:insert page="/footer.jsp" flush="true"/> </body> </html>
Consider this JSP for b.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %> <html> <body> <%-- include header --%> <tiles:insert page="/header.jsp" flush="true"/> b's body... <p> <%-- include footer --%> <tiles:insert page="/footer.jsp" flush="true"/> </body> </html>
Instead of using the JSP include mechanism, Solution 3 uses the Tiles insert mechanism. Using the Tiles insert tag, you include the view components in the appropriate positions. In all other aspects, the solution mirrors the JSP include solution (Solution 2) exactly, with the same advantages and disadvantages.
Consider this a.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %> <html> <body> <%-- include header --%> <tiles:insert page="/header.jsp" flush="true"/> <%-- include body --%> <tiles:insert page="aBody.jsp" flush="true"/> <%-- include footer --%> <tiles:insert page="/footer.jsp" flush="true"/> </body> </html>
Consider this b.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %> <html> <body> <%-- include header --%> <tiles:insert page="/header.jsp" flush="true"/> <%-- include body --%> <tiles:insert page="bBody.jsp" flush="true"/> <%-- include footer --%> <tiles:insert page="/footer.jsp" flush="true"/> </body> </html>
Solution 4 differs slightly from the Tiles insert solution. Solution 4 separates the core bodies into their individual pages, like aBody.jsp and bBody.jsp.
Consider the following JSP for aBody.jsp:
a's body... <p>
Consider the following JSP for bBody.jsp:
b's body... <p>
Solution 4's advantage: it limits body changes to the respective pages. Also, it lets you reuse the bodies in other places, eliminating the need for repetition and duplication. Thus, the solution further diminishes the coupling between common view components and other application components. Creating and managing each body component introduces an additional complexity level. As with other solutions, each page still does its own layout. Hence, there is no overarching layout policy or scheme.
Using Tiles's templating feature, you can define the following layout (from the layout.jsp file shown below) as a template. Since this is a layout, you insert placeholders instead of the actual view components using
the Tiles insert tag. Thus, for all components, this page defines one reusable layout:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert attribute="header"/>
<%-- include body --%>
<tiles:insert attribute="body"/>
<%-- include footer --%>
<tiles:insert attribute="footer"/>
</body>
</html>
Other content pages, like a.jsp and b.jsp, use the above layout for arranging components. In the actual page, you insert the layout using the Tiles insert tag. Using the Tiles put tag, you can specify the actual view components for all placeholders specified in the layout.
Consider this a.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<tiles:insert page="/layout.jsp" flush="true">
<tiles:put name="header" value="/header.jsp"/>
<tiles:put name="body" value="/aBody.jsp"/>
<tiles:put name="footer" value="/footer.jsp"/>
</tiles:insert>
Consider this b.jsp:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<tiles:insert page="/layout.jsp" flush="true">
<tiles:put name="header" value="/header.jsp"/>
<tiles:put name="body" value="/bBody.jsp"/>
<tiles:put name="footer" value="/footer.jsp"/>
</tiles:insert>
Solution 5's most significant advantage is that it encapsulates the layout scheme or mechanism, drastically reducing the coupling between common view components and other content bodies. However, it increases complexity by introducing another layout page. Understanding and implementing templating can also be difficult at first.
The above layout page, layout.jsp, contains the HTML and JSP code for organizing the components. The content pages, a.jsp and b.jsp, do not contain any HTML code; they just contain the Tiles tags to insert the necessary components. Wouldn't it be nice to
specify all the content pages in one XML configuration file?
Let's name that file tileDefinitions.xml and specify its pages as:
<?xml version="1.0" encoding="ISO-8859-1"?>
<component-definitions>
<definition name="aDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/aBody.jsp"/>
</definition>
<definition name="bDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/bBody.jsp"/>
</definition>
<definition name="cDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/cBody.jsp"/>
</definition>
</component-definitions>
Solution 6 eliminates all the content pages, like a.jsp and b.jsp, by putting their definitions in the XML file. Since a resource like a.jsp no longer exists, how can we request it? More importantly, how can we request the definitions in the tileDefinitions.xml file?
The powerful and synergistic integration of Struts and Tiles comes to the rescue. Besides the regular Struts configuration
parameters, we specify the configuration file's location as another parameter in the web.xml file, as shown below. Specifying the definitions-config parameter enables Struts to find and know about the Tiles definitions:
<!-- Standard Action Servlet Configuration (with debugging) -->
<servlet>
<servlet-name>action</servlet-name>
<!--
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
-->
<servlet-class>org.apache.struts.tiles.ActionComponentServlet</servlet-class>
<init-param>
<param-name>definitions-config</param-name>
<param-value>/WEB-INF/tileDefinitions.xml</param-value>
</init-param>
...
</servlet>
Now, we define a Struts action, which returns a definition specified in the configuration file upon success. The Struts action
DoFirst is a nonoperational action, as shown below:
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq