January
25, 2000
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.
The Problem with Straight-up Servlets
In the beginning, servlets were invented, and the world saw that they
were good. Dynamic web pages based on servlets executed quickly, could
be moved between servers easily, and integrated well with back-end
data sources. Servlets became widely accepted as a premiere platform
for server-side web development.
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.
Along Comes JSP
Around this time JSP 0.90 came along. With this new technology you
could put snippets of Java code inside your HTML, and the server would
automatically create a servlet from the page. This helped quite a
lot. There was no attempt to hide the Servlet API; JSP was considered
a "cheap" way for a Java programmer to write a servlet. All the HTML
code could be included directly without out.println() calls
and page creators could make changes to the HTML without serious risk
of breaking the Java code.
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.
Enter Template Engines
But why suffer the complexity of JSP just to do templating? Might
it not be better to use a dedicated template engine? By using a template
engine intended for this exact use instead of the general-purpose
JSP, the underlying design can be cleaner, the syntax clearer, the
error messages more meaningful, and the tool more customizable. Several
companies have built such engines, the most popular probably being
WebMacro (http://webmacro.org, from Semiotek) whose engine
is free.
Using a dedicated template engine instead of JSP offers several
technical advantages that developers should be aware of:
Problem #1: Java Code Too Tempting
JSP makes it tempting to put Java code in the web page, even though
that's considered bad design. Just as Java improves on C++ by removing
the ability to use global variables and multiple inheritance, so do
template engines improve on JSP by removing the ability to put raw
code in the page. Template engines enforce good design.
Problem #2: Java Code Required
Doing mundane things in JSP can actually demand putting Java code
in the page. For example, assume the page needs to determine the context
root of the current web application to create a link to the web app
home page:
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.
Problem #3: Simple Tasks are Hard
Doing even a simple task such as header and footer includes is overly
difficult with JSP. Assume there's a "header" template and a "footer"
template to be included on all pages, and each template includes in
its content the current page title.
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.
Problem #4: Lousy Looping
Looping is overly difficult in JSP. Here's the JSP code to iterate
over a vector of ISP objects printing the name of each.
<%
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?
Problem #5: Useless Error Messages
JSP page syntax errors can cause surprisingly odd and useless error
messages. This is due to the fact the page is transformed into a servlet
and then compiled. Good JSP tools can help narrow down errors to likely
syntax error locations, but even the best of tools will probably have
problems making all error messages meaningful. Some errors will just
be impossible for tools to diagnose, due to the transformation.
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.
Problem #6: Need a Compiler
JSP requires a compiler be shipped with the webserver. That's problematic,
especially since Sun doesn't give away the tools.jar library containing
their javac compiler. Web servers can package an outside vendor's
compiler such as IBM's jikes; however such compilers generally don't
work on all platforms and (being written in C++) aren't much help
to a pure-Java web server. JSP has a pre-compile option that can help
some here, although that's a less than elegant solution.
Problem #7: Wasted Space
JSP consumes extra hard drive space and extra memory space. For every
30K JSP file on the server there must be a corresponding larger-than-30K
class file created. This essentially doubles the hard drive requirements
to store JSP pages. Considering how easily a JSP file can <%@
include> a large data file for display, this becomes a real
concern. Also, each JSP's class file data must be loaded into the
server's memory, meaning the server may eventually store the entire
JSP document tree in memory. A few JVMs have the ability to remove
class file data from memory; however, the programmer generally has
no control over the rules for reclaiming and for large sites the reclaiming
probably won't be aggressive enough. With template engines there's
no need to duplicate the page data into a second file, so hard drive
space is spared. Template engines also give the programmer full control
over how templates are cached in memory.
There are also some downsides to using a template engine:
Template Problem #1: No Specification
No specification exists for how a template engine should behave. However,
it's interesting to note that this is far less important than with
JSP because, unlike JSP, template engines demand nothing special of
the web server -- any server supporting servlets supports template
engines (including API 2.0 servers like Apache/JServ which can't fully
support JSP)! Healthy competition for the best template engine design
could actually spark innovation, especially assuming open source implementations
that can leverage each other's ideas and code. As it stands now, WebMacro
exists like Perl, a tool where the open source implementation is the
specification.
Template Problem #2: Not Widely Known
Template engines aren't widely known. JSP has had a tremendous amount
of marketing and has gained terrific mind share. Using template engines
is a relatively unknown alternative technique.
Template Problem #3: Not Yet Tuned
Template engines have yet to be highly tuned. No performance numbers
have been taken comparing template engine and JSP performance. Theoretically
a well tuned implementations of a template engine should match a tuned
implementation of JSP; however in the world today, considering the
effort third party vendors have given to JSP so far, the odds are
good that JSP implementations are better tuned.
The Role of JSP
So is there a place for JSP in the future? Certainly. JSP is entirely
relevant if what you're trying to do is wean people off of ASP. There's
an extremely strong argument for providing something familiar looking
in a new environment. This was one of the big motivations behind the
creation of JSP, and that shows from the name -- it's no coincidence
"JSP" is just one letter off from "ASP".
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