Skip to main content

Software Development

TemplateWrapper: the inside-out JSP template

With Java web applications (JSP/Servlet) being developed in MVC style, servlets passing beans to JSPs, the order of the day is modularity and separation of concerns.  The ideal would be for the servlet programmer to forward data to the JSP in the agreed upon way and be done with it - no concerns over templating or formatting or site markup on the sender side, and especially no fiddling after the fact.  For (at least) one class of maintainance, though, it doesn't work all that well.

Suppose there is a small area on a large web site where status information is displayed.  A servlet ShowStatus fetches the status data from a database and passes it to some JSP, which displays it nicely.  Everything works fine until somebody decides that the menu, now displayed at the top horizontally, must be displayed down both sides of the page vertically.  Where's that captured?  Maybe everywhere.

If ShowStatus passes control to show-status.jsp to display the status information and it's set up with includes for the header, footer, menu bar, and so on, then it is a simple matter to edit the page to replace the single old menu include with two new menu includes.  This is not a big deal - if it takes two or three minutes to make the edit and verify it's correct, it would only take several days of tedious, error-prone work to do it for all the JSPs for one large site.  Uh oh.  This sort of problem is precisely what templating is supposed to solve, and yet it doesn't.  Templating works when content changes, such as what's in the menu bar, but not when the whole page structure changes, because templating only has "include" semantics.

If ShowStatus passes page=show-status to template.jsp to display the page skeleton then pass control to show-status.jsp for the content area, it really is only a couple of minutes' work to edit template.jsp with the new menu layout, and it's changed for every page.  This is really great until next week, when someone wants the Show Status page not to have any menu bars, the front page to have one big menu bar in the middle of the screen, and all the fields on the feedback form to be dark grey on black.  There are two ways to deal with this new request.  Since every page load goes through template.jsp, some special cases could be coded in there to use different templates for different pages - but that's putting control logic into the view, and it's going to get unmaintainable fast.  Alternatively, the control servlets that display those views could be changed to pass to a different template, but that's putting view logic into the controller, and the JSP designers will have to get a servlet programmer to make changes each time.

What if somehow the show-status.jsp could say what it wants its template to be?  With templates now, show-status.jsp could forward to template.jsp with page=show-status-body.  That solves both of the above problems, where template.jsp could be changed to edit the page skeleton globally and alternate templates could be substituted to change the page skeleton just for show-status.jsp, but it means there are twice as many files to maintain and twice as much indirection for the server to deal with.  The file designated as responsible for the view simply includes a template, which includes the file which actually presents the view to the user.  While none of these are show-stoppers, and this technique is used on real web sites to solve this exact problem, I feel that it's somehow inelegant.

What would really solve this is an inside-out templating system where the semantics are "apply" rather than "include" - the content page, show-status.jsp here, requests that a template be applied to its output, that a template wrap itself around the content.

show-status.jsp:
<t:wrap template="standard-template.jsp" contentVar="body">
<t:setVar name="title" value="System Status" />
The system is currently: <%= status %>
</t:wrap>

standard-template.jsp:
<html> ...
<title><t:getVar name="title" /></title> ...
<div id="contentfragment">
<t:getVar name="body" />
</div> ...
</html>

This is, in fact, what the TemplateWrapper tag library does.  More on TemplateWrapper over the next week or so.

Syndicate content