"Java
Servlet
Programming,
Second Edition"
"Java
Enterprise
Best Practices"
by Jason Hunter
Note: In the time since this essay was written, JSP has gone through two updates and can now be considered better (although yet more complicated) than it was when this article was written. However, JSPs competitors have not been idle and in addition to WebMacro we now have Apache Velocity and my personal favorite, Tea, from the Walt Disney Internet Group (WDIG). For an in-depth discussion of JSP and its competitors, see the 2nd Edition of my book Java Servlet Programming.
By now almost everyone using servlets has heard about JavaServer Pages (JSP), a Sun-invented technology built on top of servlets. Sun has done a marvelous job promoting JSP as a way to get HTML out of servlet code, speeding web application development and improving web page maintenance. In fact, the official "Application Programming Model" document published by Sun has gone so far as to say, "JSP technology should be viewed as the norm while the use of servlets will most likely be the exception." (Section 1.9, December 15, 1999, Draft Release) This paper evaluates whether that claim is valid -- by comparing JSP to another technology built on servlets: template engines.
However, the commonly-used simple approach to generating HTML content, having the programer write an out.println() call per HTML line, became a serious problem for real servlet use. HTML content had to be created within code, an onerous and time consuming task for long HTML pages. In addition, content creators had to ask developers to make all content changes. People searched for a better way.
But having artists and developers working on the same file wasn't ideal, and having Java inside HTML proved almost as awkward as having HTML inside Java. It could easily create a hard to read mess.
So people matured in their use of JSP and started to rely more on JavaBeans. Beans were written to contain business logic code needed by the JSP page. Much of the code inside the JSP page could be moved out of the page into the bean with only minimal hooks left behind where the page would access the bean.
More recently, people have started to note that JSP pages used this way are really a "view". They're a component used to display the results of a client request. So people thought, Why submit a request directly to a "view"? What if the targetted "view" isn't the proper view for that request? After all, many requests have several possible resulting views. For example, the same request might generate a success page, a database exception error report, or a required parameter missing error report. The same request might also generate a page in English or a page in Spanish, depending on the client's locale. Why must a client directly submit its request to a view? Shouldn't the client make a request to some general server component and let the server determine the JSP view to return?
This belief caused many people to adopt what has been called the "Model 2" design, named after an architecture laid out in the JSP 0.92 specification and based on the model-view-controller pattern. With this design, requests are submitted to a servlet "controller" that performs business logic and generates an appropriate data "model" to be displayed. This data is then passed internally to a JSP page "view" for rendering, where it appears to the JSP page like a normal embedded JavaBean. The appropriate JSP page can be selected to do the display, depending on the logic inside the controlling servlet. The JSP page becomes a nice template view. This was another improvement -- and where many serious developers stand today.
Using a dedicated template engine instead of JSP offers several technical advantages that developers should be aware of:
In JSP this is best done using Java code:
<a href="<%= request.getContextPath() %>/index.html">Home page</a>
You can try to avoid Java code using the <jsp:getProperty> tag but that leaves you with the following hard-to-read string:
<a href="<jsp:getProperty name="request" property="contextPath"/>/index.html">HomePage</a>
Using a template engine there's no Java code and no ugly syntax. Here's the same command written in WebMacro:
<a href="$Request.ContextPath;/index.html">Home page</a>
In WebMacro, ContextPath is seen as a property of the $Request variable, accessed using a Perl-like syntax. Other template engines use other syntax styles.
An another example where JSP requires Java code in the page, assume an advanced "view" needs to set a cookie to record the user's default color scheme -- a task that presumably should be done by the view and not the servlet controller. In JSP it requires Java code:
<% Cookie c = new Cookie("colorscheme", "blue"); response.addCookie(c); %>
In WebMacro there's no Java code:
#set $Cookie.colorscheme = "blue"
As a last example, assume it's time to retrieve the color scheme cookie. For the benefit of JSP, we can presume also there's a utility class available to help since doing this raw with getCookies() is ridiculously difficult. In JSP:
<% String colorscheme = ServletUtils.getCookie(request, "colorscheme"); %>
In WebMacro there's no need for a utility class and it's always:
$Cookie.colorscheme.Value
For graphics artists writing JSP pages, which syntax would be simpler to learn?
JSP 1.1 introduced custom tags (allowing arbitrary HTML-like tags to appear in JSP pages executing Java code on the backend) which may help with tasks like this, assuming there becomes a widely known, fully featured, freely available, standardized tag library. So far that has yet to occur.
In JSP the best way to do this is as follows:
<% String title = "The Page Title"; %> <%@ include file="/header.jsp" %> Your content here <%@ include file="/footer.jsp" %>Page creators must not forget the semi-colon in the first line and must make sure to declare title as a Java String. Plus, the /header.jsp and /footer.jsp must be made publicly accessible somewhere under the document root even though they aren't full pages themselves.
In WebMacro including headers and footers is done easily:
#set $title = "The Page Title" #parse "header.wm" Your content here #parse "footer.wm"There are no semi-colons or String types for designers to remember, and the .wm files are found in a customizable search path, not under the document root.
<%
Enumeration e = list.elements();
while (e.hasMoreElements()) {
out.print("The next name is ");
out.println(((ISP)e.nextElement()).getName());
out.print("<br>");
}
%>
Someday there will be custom tags for doing these loops. And custom
tags for "if" checks too. And JSP pages may look like a grotesque
Java reimplemented with tags. But meanwhile, the webmacro loop is
already quite nice:
#foreach $isp in $isps {
The next name is $isp.Name <br>
}
The #foreach directive could be replaced by a custom #foreach-backwards
directive fairly easily as well if such a thing were necessary.
Will custom tags really solve this problem? Probably not. Here's a possible <foreach> tag.
<foreach item="isp" list="isps"> The next name is <jsp:getProperty name="isp" property="name"/> <br> </foreach>Which would a graphics artist prefer?
For example, assume a JSP page needs to set a title common across all pages. What's wrong with the following?
<% static String title = "Global title"; %>Well, the Tomcat reference implementation for JSP says this is wrong:
work/%3A8080%2F/JC_0002ejspJC_jsp_1.java:70: Statement expected. static int count = 0; ^This cryptic error is trying to say that scriptlets like the above are placed inside the _jspService() method and static variables aren't allowed inside methods. The syntax should be <%! %>. Page designers won't recognize this error, and programmers likely won't either without looking at the generated source. Even the best tools probably won't be much help with errors such as these.
Assuming all the Java code could be moved out of the page, that still doesn't solve this problem. What's wrong with this expression that prints the value of count?
<% count %>The Tomcat engine says:
work/8080/_0002ftest_0002ejsptest_jsp_0.java:56: Class count not found in
type declaration.
count
^
work/8080/_0002ftest_0002ejsptest_jsp_0.java:59: Invalid declaration.
out.write("\r\n");
^
In other words, there's an equal sign missing. It should be <%=
count %>.
Because a template engine can operate directly on the template file without any "magical" translation to code, it's far easier to properly report errors. To use an analogy: When commands are typed into a command line Unix shell written in C, you don't want the shell to create a C program to execute the command. You want the shell to simply interpret the command and behave accordingly, with direct error messages when necessary.
There are also some downsides to using a template engine:
Yet there's a difference between what's suitable to someone who is new to an environment, and what's actually the best way to use that environment.
JSP is going to turn out to be one of the most important Java technologies for convincing people to leave the ASP world in favor of Java -- and hence there's a strong business case for Sun supporting it, and for any Java booster to support it.
However, that doesn't make it the best solution for the Java platform. That makes it the Java solution that is most like the non-Java solution.
This is the first in a series of articles. To be notified when new articles are added to the site, subscribe here.
Care to comment on the article? Fire an email to talkback@servlets.com. Interesting comments may be posted unless you specify otherwise.
New: Read the follow-on to this article