Systems designed without clear separation between presentation and application logic quickly become chores to maintain. Trivial look-and-feel updates in such applications take days or weeks, and trying to extend such a coupled architecture can introduce unmanageable risks and code that is impossible to unit test. To minimize the possibility of creating such disasters, avoid coupling presentation and application logic through the use of a good templating engine. Maintain clear separation between presentation and application logic from the beginning—be orthogonal. Don’t print out HTML, XML, or SQL from Java code, use a templating engine.
The simplest example of templating is Java’s
MessageFormat
. A simple message, such as
Hello {0}, I speak {1}
, can be parameterized using
the MessageFormat
class. A more complex templating
example is found in applications that use Jakarta Velocity or
FreeMarker to avoid mixing Java with HTML or textual output.
Throughout this spectrum of complexity, the concept of templating
remains the same; a template with references to variables is merged
with a context containing these variables. There are many ways to
decouple the rigors of logic from the prettiness of presentation, and
after reading this chapter, you will have a range of options for
different situations.
This chapter touches upon Jakarta Velocity, Jakarta Commons JEXL, and a technology outside of the Apache Software Foundation named FreeMarker. Templating engines are frequently used in web application, and this chapter ends with instructions for integrating these engines into a J2EE web application. Separating HTML or textual content into a separate file allows you to give graphic designers and business users a larger role in customizing and creating content for the enduser. With a templating engine, you can dramatically reduce the time and effort it takes to make simple changes. But, by far, the largest benefit of a templating engine is that it allows programmers to do more programming and graphic designers to do more designing by reducing needless coupling of presentation markup and compiled application logic.
Server-side Java has won a fair amount of attention over the past five years, but developers seldom consider using templating engines when writing a standalone Java application. Consider the following code, which prints a formatted report for a bank customer:
System.out.println( "******************************" ); System.out.println( "******* BANK STATEMENT *******" ); System.out.println( "******************************" ); Account[] accounts = AccountUtil.getAccounts("1232"); double total = 0.0; for( int i = 0; i < accounts.length; i++ ) { System.out.println( "Account: " + accounts[i].getBalance( ) ); total += accounts[i].getBalance( ); } System.out.println( "Total: " + total ); System.out.println( "******************************" );
In this example, textual content is mixed with Java code, and a programmer must be involved in any change to the look and feel of the report. If this report were generated using an external template, a nonprogrammer could be trained to change the report, or the customers could customize the output of this program by modifying a template with straightforward syntax.
Consider another common problem: generating an XML document. There
are seemingly thousands of ways to create an XML document: using DOM
or JDOM to create a Document
object, serializing
an object with Jakarta Commons Betwixt, and using
Exolab’s Castor are a few of these possibilities.
Some of these techniques are explained in Chapter 6, but here is an example of how not to generate an XML document:
System.out.println("<?xml version="1.0"?>"); System.out.println("<Config>"); System.out.println("<Property name="" + name + "" " + "value="" + value + ""/>"); System.out.println("</Config>");
Avoid this practice at all costs. Here are a few red flags from the previous two examples:
Nesting an XML document into a Java class by way of printing out
String
literals is unreadable. When you need to
mentally decode heavily escaped XML nested in Java, you are asking
yourself to do too much at once. You will also end up with mixed
context, an XML element starting within a pair of parentheses, and
ending in another. In this fugue of forward and back slashes, one
misplaced slash produces an invalid XML document, or one overlooked
NullPointerException
causes a catastrophe. You are
asking your brain to compile two strands of code with intertwined and
overlapping syntax. While your compiler might not complain, your
system will be difficult to maintain. Code that is difficult to
comprehend is even more difficult to maintain.
Escaping characters in String
literals quickly
becomes an annoyance, especially if the strings to be encoded contain
back slashes and double quotes. I accept that the
String
c: emplah.txt
, must
be written as c:\temp\blah.txt
, but I
don’t enjoy doing it. How confusing is a literal
"c:\temp\
“? Avoid this entirely by using a
templating engine or externalizing strings in properties files.
A previous example printed each account balance in a
for
loop. A common trick in JSP is to create a
while
loop with JSP scriptlets, surrounding the
code to be executed with <% while( i < 4 ) { %>
and <% } %>
. Templating
languages such as Velocity or even JSP 2.0 with JSTL support
conditional and iterative operations without asking you to mix
languages.
There are other opportunities for using a template in an application. These include code generation, creating SQL scripts, and interacting with an interpreted language via generated scripts. The list continues, and it proves that templating isn’t just for making web pages.
Examine the JSP code below (the variable names have been changed to protect the innocent). Take this code and multiply it by 100 or 200 pages. Now, what happens when you want to move from PostgreSQL to Oracle? Do you do a global search and replace on the driver class name and the JDBC URL? Or, even worse, what happens when someone asks you to translate the entire site to Chinese in two weeks? It would be easier to learn Chinese in two weeks than it would be to internationalize this code. The offending JSP is:
<% ResultSet rs; try { Class.forName( "org.postgresql.Driver" ); String dbURL = "jdbc:postgresql://192.168.0.1/dbname"; Connection dbCon = DriverManager.getConnection( dbURL, "system", ""); PreparedStatement ps = dbCon.prepareStatement( "select * from Offer " + "where id = ?" ); ps.setString( 1, request.getAttribute("id") ); rs = ps.executeQuery( ); rs.next( ); } catch( Exception e ) { %><%= Something bad happened, Call Jack (800) 232-2233 %> <% } %> <jsp:include page="header.html" /> Hello <%= rs.getString("name") %>, I would like to inform you of a good offer. <%= rs.getString("offerText") %> There are a few things I would like to tell you. <ul> <% Thing[] things = OfferUtil.getThings( rs.getString("id") ); for( int i = 0; i < things.length; i++ ) { %> <li><%= things[i].getText( )%></li> <% } %> </ul> <jsp:include page="footer.html" />
This is real code from a real system, and it was written by a whole team of programmers who didn’t find anything terribly wrong with this style. If you were raised on JSP like this, you might not recognize some of the problems. What is wrong with the previous example? Four different “languages” are combined in one file (Java, SQL, HTML, and JSP); the page starts off with JSP scriptlets, then the example contains Java code that prints out HTML and generates SQL statements. Lastly, this particular JSP page forgets to close the connection it created to the database—something that could easily create a resource leak under a heavy load. Make it simpler, use a templating engine (or upgrade to JSP 2.0) and never write a line of Java in a JSP again.
Velocity, JEXL, and FreeMarker are remedies for the coupling issues demonstrated in the previous examples. Each of these tools can be integrated into any application in a matter of minutes. In this chapter, you will learn techniques for separating presentation logic from behavioral (or business) logic. At the end of the chapter, I will briefly explain how you can integrate all of these utilities into a J2EE web application.
18.216.151.164