HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

JSP: You Make the Decision, by Jon Stevens

If you are currently looking for alternatives to JSP and you're tired of reinventing the wheel each time, then this article can provide you with the solutions you need to build your Web applications. We'll explore what it's like to develop a Web application using a couple of popular tools that are available today - and I'll use examples to show what it's like to use these technologies on a daily basis.

I'll start by comparing usage of Velocity and JSP. In both cases, we have a framework of reusable code that makes life easier for building Web applications by providing the "Model" and "Controller" portions of the MVC paradigm (Turbine and Struts). There is also a template language that provides the "View" portion (JSP and Velocity).

First let's start with some easy examples. We'll show more complicated examples later in the article.

We will not compare the feature set of each of these technologies as they both can get the job done. Instead we'll compare what it's like to do the job with each of the tools.

In the first example, we show two different approaches to doing the same thing using JSP and Velocity (see Figures 1 and 2). Listing 1 is an example of printing out a parameter with JSP, and Listing 2 with Velocity. (The listings for this article can be found on the JDJ Web site, www.JavaDevelopersJournal.com.)

Figure 1
Figure 2

The primary difference between the two is the way output is performed. With JSP you need to embed "code" within<% %> tags; you don't with Velocity. Simply use the Velocity Template Language (VTL) directly in any portion of the template.

The benefit (and detriment) of the embedded code is that the JSP code within a page won't show up when the file is simply loaded into the browser. However, there might be times when you want it to show up (for example, in debugging).

Another issue with JSP is that even the most basic examples start to blow the whole MVC paradigm right out of the water. The reason is that embedding HTML within Java code is a bad design decision; it makes it more difficult to modify the look and feel of an application at a later date. It also destroys the concept of MVC separation in which the View (HTML) display of the page is separated from the Model and Controller. For example, if just the word "Hello" had to be in bold, we would need to embed<b> </b> tags into the out.println() statement.

Of course, people in the know would recommend that we write JSP as in Listing 3, or with Struts as in Listing 4. Figure 3 shows the new JSP when the code in Listing 3 is loaded directly into the browser.

Figure 3
Figure 4

The point is, to make JSP "pure", you need to jump through hoops. Figure 3 looks similar to Figure 2, however, you still need to embed the necessary <% %> tags everywhere. More typing - more chances for mistakes! There's also a bit of a disconnect as to when the ";" needs to be added and when it doesn't. With Velocity, the rule is that you place a # before a directive and a $ before a member in the context.

As you can see from the example image, there's now a bit more information in the displayed page, except it's also missing all the logic that was used to build the page. If you view the equivalent Velocity template directly in the browser without it being rendered first, all the logic in the template remains visible. The advantage is that it's easier to debug problems.

JSP touts as an advantage that it takes an existing .jsp page and compiles it into a servlet for speed and efficiency reasons. This means that it first parses the .jsp page into a Java File, then uses javac or your favorite Java compiler (e.g., Jikes) to compile that servlet into a .class file, which is then loaded by the servlet engine.

The point is that using JSP is now a multistep process. The authors of JSP have done a good job of hiding this process behind the scenes in such a way that you don't even notice it. You simply edit the .jsp page in their favorite editor and then use their browser to call the page via a URI that starts the process of transforming it into a .class file.

This whole process of edit->transform->compile->load->run is really unnecessary and, in particular, a bad design. The reason is that it could be made much simpler.

Velocity simply loads templates, parses them a single time, and then stores an Abstract Syntax Tree (AST) representation of the template in memory, which can then be reused over and over again. The process is simply edit->parse->run. The benefit is that working with Velocity templates ends up being much faster and it also eliminates the requirement of having a javac compiler and temporary scratch directory hanging around. In Velocity, when the template changes, the existing cached template is simply replaced with a freshly parsed version.

Another advantage to Velocity's approach to templates is that the actual template data can be stored anywhere, including a database or remote URI. By using configurable template loaders, it's possible to create template loaders that can do anything you want.

Even without Turbine, Velocity offers several ways to deal with errors. Frameworks such as Struts and Turbine come in handy by providing ways of properly dealing with errors. However, since Struts is based on top of JSP, it also inherits the same amount of problems associated with JSP. The next section discusses it in more detail.

One final problem, shown in Figure 4, is that the JSP page catches only exceptions. What if the code within a JSP page throws another exception like OutOfMemoryError? The problem here is that OOME is based on throwable, not exception. Therefore, it's much more difficult to catch this exception with just a JSP page. Future versions of the JSP spec and implementations will improve on this.

Figure 4, provided by our friends at NASA, sends multibillion=dollar equipment through the heavens; it's a perfect example of why JSP needs better error handling.

Buffering is also another big issue since constantly writing to the output stream is not very efficient.

<%@ page buffer="12kb" %>
<%@ page autoFlush="true" %>

These examples tell JSP to buffer the output 12KB and to autoFlush the page. Struts plus JSP has implemented the MVC model by providing the View portion through JSP templates. What part of the MVC model do you think those tags belong to? You guessed it, not the part where they're being used.

Velocity deals with this issue by allowing the developer to pass a stream into the rendering engine. If there's an exception thrown during rendering, it can be caught and dealt with. Buffering is also handled by passing a properly buffered stream to the parser. Again, if there's an error, another stream can be easily substituted for the output.

Listing 5 provides an example of the intermediate code generated by Tomcat 3.3m2.

Error Handling
This is a good one and a fundamental design issue with JSP. The question is: How many different types of errors can you get when using JSP? For example, because the JSP servlet is autogenerated from a .jsp text file and then compiled with a compiler, what happens when there's a generation/parsing error or a compile error? The unnecessary complexity of JSP actually increases the number of ways to get errors.

The ugliest aspect of all of this is that the errors are reported via two different mechanisms. The parser can throw one set of errors and the javac compiler can throw a whole different set of errors and, as a result of the layers of generation, errors from the compiler generally don't make any sense whatsoever. For example, can you tell me what this error is from?

org.apache.jasper.JasperException: Unable to compile
class: Invalid type
expression.
out.println("JSP is great!")
^
: Invalid declaration.
out.write("\r\n\r\n\r\n");
^
2 errors

If you guessed that it was a result of a missing ";" after the first out.println(), you were correct. Now, put yourself in the shoes of someone who has never written or seen a line of Java code. Do you think that person could have figured out the error quickly and easily? Compound that with the fact that if the error had been on a less deterministic part of the file, it would be much harder to find the source of the error because there's a level of abstraction from the original .jsp file and an intermediate .java file that gets generated.

Again, Velocity doesn't suffer from these same problems because there's no intermediate step and no layers of abstraction.

<%@ page errorPage="/error.jsp" %>

JSP also allows you to define an error page that's used if a throwable exception is thrown during the processing of a page. Doesn't this again break the MVC model? In other words, shouldn't the application framework be responsible for dealing with error messages?

<% throw new Exception("oops"); %>

To throw an Exception somewhere in a JSP page, you need to first embed it within a statement. Note: In this specific case, if optimizations are turned on in the compiler, chances are the entire exception would be compiled out. Therefore, a more concrete object must be used instead of the "true." This can actually prove difficult if using a strict MVC model because instantiation of objects breaks the View.

<%
if (true)  {
throw new Exception("oops");
}
%>

The reason is that JSP will generate an additional out.println ("\r\n"); after the Exception. When javac attempts to compile the page, another hard-to-debug error will be reported:

org.apache.jasper.JasperException: Unable to compile
class for
JSPC:\engines\jakarta-
tomcat\work\localhost_8080%2Fjsp\
_0002ferrorMaker_0002ejsperrorMaker_jsp_3.java:75:
Statement not reached.
out.write("\r\n");
^

Taking a direct quote out of Jason Hunter's book, Java Servlet Programming (I couldn't say it better myself):

In fact, there are many such "gotchas" when using scriptlets with JSP. If you accidentally write a scriptlet instead of an expression (by forgetting the equal sign), declare a static variable inside a scriptlet (where statics aren't allowed), forget a semicolon (they're not needed in expressions but are needed in scriptlets), or write anything but perfect Java code, you're likely to get a confusing error message because the compiler is acting on the generated Java code, not on the JSP file. To demonstrate the problem, picture if <%= name %> were replaced by <% name %> in errorTaker.jsp. Tomcat generates this error:

org.apache.jasper.JasperException: Unable to compile class
for
JSPC:\engines\jakarta-tomcat\work\localhost_8080%2Fjsp\
_0002ferrorTaker_0002ejsperrorTaker_jsp_6.java:91:
Class name not found.
name
^

Debugging an error like this often requires a programmer to look at the generated code to reconstruct what caused the error.

Velocity doesn't have these same problems since it doesn't allow the author to place any Java code within a template. The only things allowed in the template are Velocity Template Language (VTL) and method codes.

Everything else is considered "text" for literal output by the parser. The only place where you could run into trouble within Velocity is if there's a call to a method that throws an exception during runtime. For example, this VTL defines a string $foo, but attempts to call its substring() method on it would throw an IndexOutOfBoundsException:

#set ($foo = "bar")

#set ($bar = $foo.substring(0,10))

When the exception is thrown, the parser will stop processing and throw that exception up the stack tree where it can be caught in the method that caused the parser to execute. At that point, the exception can be handled gracefully. Yes, this is something that's not easily debugged by a designer who doesn't know Java; it's easily debugged by a template engineer who has limited Java knowledge.

This is one of the benefits of using Turbine combined with Velocity: because of Turbine's design it's easy to deal with Exceptions in a consistent manner. It's also possible to get this same functionality by using Velocity's included VelocityServlet. The Exception will contain the line and column numbers in the .vm file where the error happened. Since there's no abstraction as with JSP, the line number and column matches up to the error. Also, the only tool that will throw the Exception is the Velocity parser, and that Exception will contain the location and error information pertinent to your actual template, not an intermediary file. No need to try to debug the cryptic javac messages that are a result of generated Java code. Note: Some application servers offer better handling of matching the line number in the JSP file to the error.

JavaBeans
JavaBeans are the way to use Java objects from JSP pages in order to follow the MVC design pattern. The point of doing this is to implement something similar to the Pull methodology, for example:

<jsp:useBean id="name" scope="page|request|session|application" class="className" type="typeName">

Examining the syntax of the above code, the first thing that pops up is the use of the scope attribute. How many HTML designers understand the programming concepts of scope? It's safe to suggest that a good portion of Web designers barely understand the concept of how a CGI works. By stating this, we're not trying to slight people. Instead, we're simply pointing out that design and software engineering are distinct skill sets. You wouldn't expect a Java programmer to select a print- and Web-safe color palette, would you?

The common response to an argument like this is that the designers should simply ignore these tags and let others define and implement them. The problem with that is that you've now given them the power to accidentally wreck your entire application in such a way that it's very difficult to debug because a complex scope issue might not show up right away.

The Java code:

public class HelloBean  {
private String name = "World";

public void setName(String name)  {
this.name = name;
}

public String getName()  {
return name;
}
}

The JSP code:

<jsp:useBean id="hello" class="HelloBean">
<jsp:setProperty name="hello" property="*" />
</jsp:useBean>
<HTML>
<HEAD><TITLE>Hello</TITLE><HEAD>
<BODY>
<H1>
Hello,<jsp:getProperty name="hello" property="name"/>
</H1>
</BODY>
</HTML>

The above code is a simple example of using a bean in a page. Pass the bean some properties and then retrieve the results. This is the right way to do things when using JSP. However, if we look at an example of the same thing in Velocity, the extra amount of typing that you need to perform to simply retrieve a property seems a bit much. Of course, there are always GUI-based, drag-and-drop tools to make typing a thing of the past. Really.

There are several commercial solutions available that provide a nice drag-and-drop view for developing with JSP and Struts. However, many of these tools are still first generation. They typically address only parts of the problem and require digging down into the nitty-gritty stuff when things become difficult or even impossible to do with the GUI. Often these tools also produce code that isn't optimized for heavily hit sites, and getting an existing application to scale sometimes requires a complete rewrite. Another item to note here is that these are costly ($1000/seat) development tools. In this economy, who really has the money to spend on these tools?

The Java code:

context.put ("hello", new HelloBean());

The Velocity code:

$hello.setName("*")
Hello, $hello.Name <HTML>
<HEAD><TITLE>Hello</TITLE><HEAD>
<BODY>
<H1>
Hello, $hello.Name
</H1>
</BODY>
</HTML>

This code example creates the HelloBean() object and then places it into the context. Then, during runtime execution of the template, that object is available as a $variable that uses the JavaBean specification to do introspection on the object. For example, Velocity uses bean-style introspection to permit the method call to be shortened from $hello.getName() to simply typing what's shown above.

When Velocity is combined with Turbine, the HelloBean object can be added into the context as a configuration option or it can be added at any point in the processing. This is what provides the "scope" of the object in the context.

Another "gotcha" with using JavaBeans in JSP is again quoted from Jason's book:

One thing to watch out for: On some servers (including Tomcat 3.2) if you have a bean with a scope of "session" or "application" and you change the bean class implementation, you may get a ClassCastException on a later request. This exception occurs because the generated servlet code has to do a cast on the bean instance as it's retrieved from the session or application, and the old bean type stored in the session or application doesn't match the new bean type expected. The simplest solution is to restart the server.

Sample Application
Velocity developers believe that you shouldn't have to specially code your applications to work around issues that are related directly to Java.

In other words, one of the strong arguments of the JSP/Struts community is to say something to the effect of: "This is a poor example of using JSP." While this may be true, the fact is that nearly every example available is a poor example of using JSP. This goes back to the statement: embedding Java code in your page is a bad thing. Yes, we all know that now.

The truth is, it's hard to use the tool correctly. Struts is doing an excellent job of making it easier and attempting to show the right way, however, it's simply hiding the ugliness of the original design of JSP.

Object-oriented design dictates that you extend a class to add functionality to the base class. The publicly available methods in the base class are still available to the classes that extend it. Putting Struts on top of JSP doesn't fix the warts in JSP. It simply hides them until your developers find them (see Listing 6).

Listing 7 translates Listing 6 to Velocity.

Taglibs
Taglibs are intended to be the savior of JSP. They're billed as the way to extend JSP so that there's a nice MVC abstraction while still adding functionality to the base "language." Struts has concentrated a good portion of its efforts here by providing a nice taglib library.

The advantage of using taglibs is that they allow you to extend the "language" syntax of JSP so you can provide the things that are missing from it, but are available in Java. In other words, instead of encouraging people to embed Java code within their pages, this has been abstracted to encouraging people to embed XML tags in their page. How is this any better than what ColdFusion did with their product? Sure, plenty of people are using ColdFusion, but is that the best way to do things?

Listing 8, borrowed directly from the Struts documentation, shows how logic would be embedded into your JSP page.

Listing 9 shows the same example using Velocity.

Of course Listing 9 could be written even cleaner as:

#if($number == 7)
You guessed right! You win a high speed blender!
#elseif( $number< 7 )
lower
#else
higher
#end

This really falls into a preferences situation. In other words, which syntax would you prefer to use? It seems as though the amount of typing required to implement the taglibs approach would be a major deciding factor for many people. One reason is that the more typing that needs to be done, the more chances for errors. Listing 10 provides another example taken from the Struts documentation.

It's clear from Listing 10 that the whole strict MVC model has been broken again because a call to java.util.ArrayList and creating an Object is embedding Java code within a template. Compound that with the need to place that ArrayList into the pageContext makes it even more confusing. In addition, the designer has to remember to use cryptic code at the top of the file that references a taglib document as well as declares a prefix attribute. Why do things need to be so overly complicated?

The same example using Velocity would be written like this:

#set ( $list = ["First", "Second", "Third", "Fourth", "Fifth"]  )

#foreach ( $item in $list )
Element Value: $item

#end

Moving on with examples, we come back to the previous sample application from Jason Hunter's book that was shown before. This time it has been implemented entirely within the Struts framework (see Listing 11).

At this point, we now have a combination of standard JSP tags as well as Struts-specific tags. The use of Struts has appeared to clean things up significantly with regards to embedded scriptlets. Note that quite a few of JSP's warts are still shining through. Is it as easy to understand as the Velocity version?

Velocity provides a simpler solution designed around a few core template tags. A scripting language is similar to PHP, which may require months of usage to completely master. A template language can be mastered in just a few hours. This is what makes Velocity a template language instead of a scripting language.

For example, Velocity has the following core template tags (otherwise known as "directives"):

#if
#else
#elseif
#foreach
#set
#parse
#include

It's possible to add more #directives to Velocity either by adding them directly to the parser or through an API. It's also possible to use a neat feature of Velocity called Velocimacros, documented at http://jakarta.apache.org/velocity/user-guide.html#velocimacro.

Some people suggest that the benefit of using JSP and Struts is that they simply extend HTML, something designers already understand. This is a powerful argument. However, the reality is that HTML is not a template language; there's no logic in HTML. For example, it's not possible to embed conditional statements (as in Listing 1) into HTML.

What this means is that taglibs allow developers to infinitely extend HTML to become much more than it previously was, almost like inventing another scripting language. This is reminiscent of the early browser wars in which each company was implementing their own browser tags. Netscape went so far as to invent the <blink>tag. What did we learn from that? Is that really a good thing? Sure, standardizing taglibs is a great idea. Will it ever become widely adopted? We sure hope so.

One last point to make about using HTML syntax is that this really pigeonholes JSP and Struts into simply being tools for creating dynamic HTML/XML/WML (tag markup) code. Velocity on the other hand is designed to take any type of text (Java, SQL, HTML, etc.) as input and output anything as a result of running it through its processing engine.

Embedded Usage
The following is an example of using Velocity within an application.

OutputStreamWriter writer = new
OutputStreamWriter(output, encoding);
Template template = RunTime.getTemplate(filename);
template.merge( context, writer );

In other words, the above is translated into:

  1. Create a Writer.
  2. Ask the Velocity RunTime to retrieve the Template.
  3. Merge the Context with the Template.
Velocity templates can contain *any* type of data - XML, SQL, HTML, plain text, internationalized text - anything. The parser is very robust in terms of parsing out only what it cares about and ignoring the rest. As just demonstrated, it's possible to embed Velocity's template engine into any other Java code. The advantage of this is that it provides users with a single template system for all sorts of uses.

For example, in the PetStore example on the J2EE Web site, http://java.sun.com/j2ee/maroonprints/sample_application/index.html, there's a JavaBean that sends an e-mail confirmation when an order is complete. The unfortunate part about this example is that in order to change the contents of the e-mail, you need to edit Java code. Of course, this example could have been done differently to use a JSP-based template as the base format. However, the implementation of this is more difficult than simply creating a Java object that resides in the context and can render the template as arguments.

Another example of this is the Texen and Anakia tools that come with Velocity. The advantage again is the ability to use Velocity as an embedded tool to produce other useful applications that are not bound strictly to a Web application. While it's possible to do this with the JSP engine, it's significantly more difficult.

Implementation
One of the touted advantages of JSP is that it's a "standard" and quite a few people like to hold this in high regard. So much so that they refuse to use any technology that's not "standard." Digging into the reality of this statement reveals that the important correct terminology is that JSP is a "Sun Standard Specification," not strictly a "standard." This is important because JSP is really no more "standard" than Microsoft ASP or the PHP Group's PHP product. In other words, whatever tool you happen to be using becomes the "standard."

A small group within the Java Community Process (JCP) defines what JSP is. There's a fairly high barrier to joining the JCP because an NDA must be signed, the project leads must approve your entry, and in some cases a fee must be paid. You could even go as far as to say that the JSP specification is really a proprietary product of Sun.

It's important to note at this point that I'm a member of the JSR-053, which defines the Servlet and JSP specifications.

Inside JSR-053 it's clear that not everything is done in the open and decisions are made behind closed doors. Of course, the participants could object, but Sun still is the binding force behind the decisions.

JSP is both a specification and an implementation. There are various corporations (as well as open source) implementations of the specification. The JSP specification isn't a particularly easy thing to implement. There are many complex systems involved, some of which even require special hooks into the servlet engine in order to obtain optimal performance.

The JSP specification is relatively new (it's still in a 1.x phase). This means that the specification also has several places in it that are not as well defined as others, leaving some of the specific details to be determined by the implementation. Not only does this mean that there are plenty of places to make mistakes, but it also means that JSP template code might not behave the same across implementations. This makes testing JSP-based applications across several different containers a nightmare, especially if there are esoteric bugs (meaning bugs that show up only under extreme conditions) in one and not the other.

Part of the reason for creating the Jakarta Project and having Sun release the source code to Jasper (the JSP reference implementation) is to encourage vendors to adopt a single base for their source code. Unfortunately, this has not happened. There are compatibility testing suites available; however, there's no policy in place requiring vendors to pass the tests. Nor is there a place that shows vendors who don't pass the tests in order to publicly humiliate them into submission.

The user and developers of the velocity project are the ones who define the Velocity specification. They've created a comprehensive testing suite that's used for regression testing to ensure that all changes to Velocity won't break existing templates. If you or your company ever want to join the development of Velocity and help determine its direction, that can be easily done by simply joining a mailing list and contributing to the development effort. This means that no one corporation will ever own the Velocity specification and that it will always work with your templates within any servlet engine.

Hosting
JSP is great for hosted environments (e.g., shared development environments, ISPs, and large companies) in which many different kinds of people who are putting pages on the servlet engine may not know much more than HTML. One reason it's so nice is that with the HTML'ish syntax, JSP is so easy to learn.

However, if you look at that statement in more detail it becomes apparent that this might not be such a good thing. Consider the following snippet of Java code:

Hashtable strings = new Hashtable();
int i=0;
while  (true)
{
strings.put ("dead"+i, new StringBuffer(999999));
}

This creates a Hash table and then goes into a tight loop. At the same time it creates a new StringBuffer object that has a default size of 999999, creating what amounts to a memory leak in the Java Virtual Machine (which all the hosted applications share).

As soon as all the memory is gone, every single hosted application will start to receive the dreaded "OutOfMemoryError." The reason why this is so bad was explained earlier. Essentially, JSP pages can't catch OOME errors and the entire servlet engine will suddenly become useless, all because of a few lines of badly written Java code.

Remember, it's a bad idea to put Java code into a JSP page. Tell that to the 14-year old kid who is being hosted on your ISP's servlet engine and really doesn't care that others might be affected by these actions.

Velocity doesn't have this issue because there's no while loop in the Velocity Template Language. The only looping construct in Velocity is a #foreach and that loops over an array that has a finite amount of elements. It's also possible to disable the #foreach directive and limit the amount of recursive nesting that's possible.

Currently, there's nothing in JSP or Struts that prevents people from embedding Java code in the page. As a result, Sun has developed a way to validate JSP pages so that they conform to a specification that you can define. In the end, this results in the need to remove the ability to place scriptlets into the templates. However, scriptlets are a major part of JSP - and the examples people give show that this effectively will break nearly every template in existence.

Conclusion
We hope that you enjoyed this little excursion into the land of alternatives. Every developer and user in the world has his or her own opinion on the "right way" to do things. The goal of this document is not to force you to believe that the Velocity way is the "Right Way," but to let you see the differences between the two approaches and develop your own opinions about the tools that are in use today.

Some people may disagree strongly with this article because it challenges conventional thinking as well as the way that they may be doing things today. It's difficult to show people who believe strongly in something that there might be another solution out there that solves problems in a different way. So please send us your feedback.

Author Bio
Jon Stevens is an Apache Software Foundation Member and the cofounder of the Java and Jakarta Apache projects. He is a cofounder of the Velocity and Turbine projects. He has been developing Web applications since 1994 in various languages and platforms. In 1998, he started to build the Turbine framework in an effort to develop open source tools to help developers build complex Web applications. [email protected]

Download Assoicated Source File (~ 40.0 KB)

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.