Dedicated Template Languages

If we're only using JSP pages for views, we're using JSP pages as templates. If we base our JSP usage on the JSTL, we're largely abandoning the original JSP idea of using Java as the scripting language.

Since we don't want to use the request handling capability of JSP pages or the power of Java scripting JSP pages offer and believe that the availability of these features may actually be harmful, it's reasonable to question why we should be using JSP at all.

There are many alternative template languages to JSP, available in open source (XSLT deserves its own section and is discussed later). Unlike JSP, these are designed purely as template languages. Each has its own merits and flaws, but there is much similarity between them. First let's consider the big picture, and the pros and cons of using a template solution, rather than JSP.

Common Concepts

The templating solutions we'll discuss in this section share the following basic concepts:

  • A template is purely a view. It is restricted to simple conditional logic and iteration and does not attempt to offer the power of a true programming language.

  • For this reason, template languages are simple and easy to learn.

  • Data must be made available to the template by a controller. Unlike JSP pages, templates have no way of obtaining data themselves, for example from the request object or any user session. Exactly how a model is made available to the template varies with the individual product.

  • Using a template involves a two-step process, using a template-manager specific API: Obtain a template instance from the file system or classpath, and use the template with the given model data to generate output and write it to the response.

Why might we choose to use a template language for web tier views in place of JSP?

  • Using a template language promotes good design. As we've seen, JSP makes it easy and tempting to use an inadequate "Model 1" architecture or to subvert MVC architecture. By using a template language, the role of a view is made explicit.

  • Most template languages do a better job of matching the appearance of a template page to that of the markup it generates than JSP. This makes life easier for page designers.

  • Template languages offer simpler syntax than JSP. JSP scriptlet syntax is messy, while JSTL and other custom tags require the use of markup, which is not the most natural way to handle control flow to either a Java developer or a markup author.

  • Most template languages are not tied to the Servlet API. This means that they can be used in other situations to leverage the investment in adopting them (for example, generating static pages), and that template development and testing can be done without running a J2EE server.

However, there are also disadvantages in using a dedicated template language:

  • In contrast to JSP and the JSTL Expression Language, no template language is a recognized standard. Given that most template languages are very simple and there's no significant learning curve required, this is not as major a stumbling block as it appears. Furthermore, JSP pages are often edited by markup developers with a very sketchy grasp of Java and JSP syntax. However, the political reality is that in many projects it will simply be impossible to achieve acceptance of technologies outside the J2EE standards for which a "standard" alternative exists, regardless of the grounds for preferring them.

    With appropriate choice of templating technology, there is little risk of committing to a template language that will not survive (the classic argument in favor of "standard" solutions): there is little doubt that leading template languages, such as Velocity, are viable and here to stay.

  • We need to distribute runtime libraries as part of our application. JSP is guaranteed to be available in any J2EE-compliant web container, although it's presently necessary to distribute the binaries for JSTL. However, WARs give us a standard way to include library classes, so this isn't a major problem.

While JSP pages, which are compiled into servlets, might be expected to outperform templating solutions, the reverse may be true in practice. We'll discuss view performance in Chapter 15.

Let's look at some popular templating solutions.

WebMacro

WebMacro is one of the oldest and best-known Java-based template languages.

The following excerpt from WebMacro documentation, quoted with the author's permission from http://germ.semiotek.com/README.html, highlights the differences from JSP and makes the case for using a specialized templating solution instead of JSP:

'WebMacro is similar in many ways to JSP/ASP and other projects in many ways, but differs from those according to our biases:

  • We think it is wrong to use markup for a scripting language

  • We think it is wrong to embed programs on a web page

  • We think it is wrong for web scripts to look like hard programming

  • We feel that an API like WM should make it easy to do the things you need to do when designing and deploying applications

  • We believe that programming and graphical page designs are separate tasks

WebMacro uses a simple syntax that doesn't require escaping into and out of scripts, as does JSP pages. Not being markup based, the syntax is more intuitive than using JSP custom tags. The following example shows how WebMacro can be used for a conditional statement, based on a JavaBean property. Note that the bean scripting variable is prefixed with a $:

    #if ($bean.GoldService) {      <font size="4">Welcome to our Gold Service!</font>    } #else {      <font size="4">Welcome!</font>    } 

JavaBeans are made available to WebMacro templates by being placed in a WebMacro context, which contains objects used similarly to the use of HttpServletRequest attributes in JSP pages.

Like JSTL, WebMacro supports nested property paths such as person.spouse.name. It is also possible to create new variables, perform iteration, calculations etc.

While the syntax differs slightly, the concepts are virtually the same as those of Velocity, discussed below, so I won't discuss the WebMacro template language here. Please refer to http://webmacro.org/WebMacroBasics for more information.

WebMacro is proven on real web sites. Since January 2001, AltaVista, one of the most heavily trafficked sites on the web, has been using WebMacro as its primary page generation technology. WebMacro is available from http://webmacro.org, and is free under the Gnu GPL.

Note 

The framework code with the sample application includes an implementation of the View interface, com.interface21.web.servlet.view.webmacro.WebMacroView, which allows the MVC framework we discussed in Chapter 12 to be used with WebMacro templates. Use this class (remembering to include the WebMacro JAR file in your WAR's /WEB-INF/lib directory) to use WebMacro templates with this framework without any need to change controller or model code. This view implementation is very similar to the Velocity implementation we'll discuss below, so I won't discuss it here.

Velocity

Jakarta Velocity is essentially a re-implementation of WebMacro with a distinct codebase and some new features. For a discussion of Velocity's relationship to WebMacro, see http://jakarta.apache.org/velocity/differences.html. Velocity has more comprehensive documentation than WebMacro, is published under a different license and the Velocity project seems more active.

In this section we'll look at Velocity's basic concepts, and see how our example view can be rendered by a Velocity template.

Velocity Concepts

Velocity is purely and simply a template engine. This makes Velocity easy to learn and avoids the common problem of a framework providing its own implementations of concepts that are already well handled by other products. The Velocity template engine does not depend on the Servlet API, meaning that it can be used for applications other than web applications, and that Velocity templates can be tested outside a servlet container (a significant advantage over JSP).

The heart of Velocity is the Velocity Template Language (VTL), Velocity's equivalent of the WebMacro language. VTL looks very like the WebMacro template language. There is no need to escape expressions or "scriptlets". The # character is used to prefix directives (control statements), and the $ character to prefix variables. Both these characters can be escaped if they are part of static template data.

Velocity has a slightly different philosophy to WebMacro, aiming to keep the set of core directives to a minimum, while allowing users to extend Velocity's capabilities for their applications by defining Velocimacros: reusable template segments that can be used like Velocity directives. Macros can define any number of arguments to be passed on invocation. The following simple macro, with a single argument, outputs an HTML-formatted list of squares from one up to a given maximum value, and illustrates the basic Velocity syntax:

    #macro( squareList $upTo )      <ul>      #foreach ( $item in [1..$upTo] )        #set ($square = $item * $item)        <li>$square      #end      </ul>    #end 

This macro can be invoked within a Velocity template as follows:

    #squareList(6) 

Velocity macros can be declared "inline" in Velocity templates (although this can be disabled if desired) or collected in template libraries, analogous to JSP tag libraries. Velocity macros are in some respects what JSP custom tags should have been: simple and defined without the need to program in Java (JSP 2.0 will introduce simpler tag extension definitions that are closer to this).

As with WebMacro, model objects used in Velocity templates must be made available to Velocity in a Velocity context object. Templates can easily expose bean properties, including nested properties, for objects placed in a Velocity context.

Unlike JSP pages, but like WebMacro templates, Velocity templates don't declare model objects required in their context using a comparable mechanism to <jsp:useBean>. Variable references that can't be resolved in the context will appear as literals, making it easy to rectify typos (for example, if there is no model object called nothing, $nothing will appear as a string literal in the template output). The absence of variable declarations and type checks may be off-putting to a Java developer, but web tier presentation templates aren't intended for Java developers to edit.

Velocity comes with a JSP custom tag that interprets its body content as VTL. When using Velocity, there's little reason to use JSP as a wrapper, and mixing JSP and VTL allows all the negatives of JSP plus a mixture of technologies to make maintenance still harder. However, there are a few situations when the Velocity tag library might be useful:

  • Where the overall page must be generated by JSP.

  • Where you want to use a feature of JSP that Velocity doesn't offer, but which is a valid view operation. For example, if you want to use a particular tag library.

I won't attempt to describe VTL syntax in detail here. A good, concise VTL reference guide is included with the Velocity distribution. Instead, let's look at using a Velocity template to display our sample view.

A Velocity Template for our Example

Our MVC web framework provides standard support for Velocity views. We can define a Velocity view bean for the sample page in /WEB-INF/classes/views.properties using the com.interface21.web.servlet.view.Velocity.View standard View implementation. This standard View implementation will obtain and cache the associated Velocity template on startup. When asked to render a model to the response, it creates a Velocity context with an attribute corresponding to each entry in the model. This is analogous to the way in with the InternalResourceView copies model entries to request attributes. It then uses Velocity to write output to the response, given the template and context data.

Note 

See Appendix A for information on how this view is implemented, and how to install and configure Velocity.

The most important bean property to set on the VelocityView class is the templateName property, which identifies a Velocity template within the WAR. We can define our sample view as follows:

    showReservation.class=com.interface21.web.servlet.view.velocity.VelocityView    showReservation.templateName=showReservation.vm    showReservation.exposeDateFormatter=true    showReservation.exposeCurrencyFormatter=true 

Note that this bean definition also sets the two format helper properties to true, which causes the VelocityView class to add DateFormat and NumberFormat helpers with the names simpleDateFormat and currencyFormat to the Velocity context, which the template can use to format dates and currency amounts. This functionality, provided by the VelocityView framework class, is necessary since Velocity 1.3 (surprisingly) provides no standard support for date and time formatting (this issue is discussed further in Appendix A).

The first task in writing the Velocity template (found in the sample WAR at /WEB-INF/classes/showReservation.vm) is to set the pattern used by the date helper and to create variables containing the formatted dates and times. As we're reliant on Java support for this, the code we'll use is similar to that used in our JSP example:

    <!--    $simpleDateFormat.applyPattern("EEEE MMMM dd, yyyy")    #set ($formattedDate = $simpleDateFormat.format($performance.when) )                                                         $simpleDateFormat.applyPattern("h:mm a")    #set ($formattedTime = $simpleDateFormat.format($performance.when) )                                                         --> 

Note that I've placed the Velocity "scriptlet" in an HTML comment. It won't actually generate output, but this will avoid it upsetting HTML editing tools. The #set directive enables us to declare variables used later in the template.

Once this is out of the way, the rest of the template is easy and intuitive to write. Note the simple access to nested properties. Our model objects, once placed in the Velocity context, can be accessed by name:

xs    <html>    <head>    <title>Seats reserved for $performance.show.name</title>                                                                     </head> 

We can now output our formatted date and time:

    <body>    <b>$performance.show.name:    $formattedDate at $formattedTime                                                                                             </b>    <br/>    <p> 

Although Velocity allows us to invoke methods, as well as get property values (by using parentheses, even if methods take no arguments), it doesn't allow us to find the length of an array. Fortunately the number of seats is also available from the quoteReservation property of the Reservation object, so we can take a roundabout route:

    $reservation.quoteRequest.seatsRequested    seats in    $priceband.description    have been reserved    for you for    $reservation.minutesReservationWillBeValid minutes to give you time to complete your purchase 

Velocity shines in iterating over the seat array. Like JSTL (but not JSP scriptlets) Velocity exposes each item in turn as a variable, making this code very simple. Velocity's syntax is simpler and more intuitive than the JSTL markup-based syntax:

    The seat numbers are:    <ul>    #foreach ($seat in $reservation.seats)        <li>$seat.name    #end                                                                                                                         </ul> 

Note 

Velocity also allows us to find the position in the list through the value of the velocityCount predefined variable, although we don't need this capability in the example.

We use the NumberFormat helper object to format the currency amounts, meaning that we don't need to supply currency symbols. The NumberFormat class will always return the one appropriate for the request locale:

    The total cost of these tickets will be    $currencyFormat.format$reservation.totalPrice).                                                                              This includes a booking fee of    $currencyFormat.format($reservation.quoteRequest.bookingFee).                                                             

Conditionals such as our check as to whether the seats are adjacent use the Velocity if directive. Note the closing #end directive:

    #if (!$reservation.seatsAreAdjacent)                                                                                           <b>Please note that due to lack of availability, some of the      seats offered are not adjacent.</b>      <form method="GET" action="payment.html">        <input type="submit" value="Try another date"></input>      </form>    #end                                                                                                                      

Displaying the seating plan image URL involves another nested property. Note the use of what Velocity documentation calls formal notation (with the variable name enclosed in curly brackets), which enables us to distinguish the part of the string that is a variable from literal text in the same way as we used the JSTL ${} expression delimiter:

    <img src="/books/1/392/1/html/2/static/seatingplans/${performance.show.seatingPlanId}.jpg" /> 

Comparing this with the JSTL alternative shows the similarities between accessing bean properties in JSTL and Velocity and the disadvantages of markup-based scripting. The JSTL version involves nested <img> and <c:out> tags, while the output, of course, will include only the <img> tag we're actually trying to generate:

    <img      src="/books/1/392/1/html/2/<c:out      value="static/seatingplans/${performance.show.seatingPlanId}.jpg" />"    /> 

Note how both are less verbose and error-prone than the standard JSP way, which is awkward, even when broken into one scriptlet and an expression:

    <% String seatingPlanImage = "static/seatingplans/" +            performance.getShow().getSeatingPlanId() + ".jpg"; %>    <img src="/books/1/392/1/html/2/<%=seatingPlanImage%>" /> 

Velocity Summary

Velocity offers a very simple, high-performance, template language that is well suited to exposing JavaBean properties. Velocity isn't web-specific.

Property navigation syntax in Velocity is much like that in the JSTL. The simple Velocity scripting language uses special characters to identify directives, rather than escaping to and from embedded code, as in JSP scriptlets, or markup, as in JSP custom tags. Thus the Velocity template for our example is more concise and easier to read than even the JSP version using JSTL.

While the J2EE-standard argument for JSP is compelling, personally I find that comparing at a Velocity or WebMacro template with a JSP presenting the same information shows how verbose and unintuitive the JSP syntax is, and that custom tags (and the prospect of JSP 2.0) merely reduce the gap. While Java developers tend not to question the readability of JSP pages, in my experience HTML developers, who will have to work with them, find them awkward and alien.

Both WebMacro and Velocity are good, usable solutions that enforce a clean separation between control logic and view template. Although I've chosen to use JSP as the main view technology for the sample application, as the above example shows, using Velocity would probably result in simpler, more readable view templates.

FreeMarker

FreeMarker is conceptually similar to WebMacro and Velocity in that a template is obtained using the provided API and used to render a model constructed using method calls. The FreeMarker template language has a more markup-oriented syntax to WebMacro and Velocity, but is comparable in power.

However, unlike WebMacro, Velocity, andJSP, FreeMarker attempts to avoid the use of reflection to obtain model values, presumably because of concerns about the performance of reflection. This means that adapters must be written as part of application code to expose data to FreeMarker (these adapters are analogous to Swing models). While it's possible to add anyJavaBean into a WebMacro or Velocity Context and access its properties and methods without writing any additional Java code, FreeMarker requires explicit coding.

The FreeMarker equivalent of a WebMacro or Velocity context is a "data model tree",in which the root must implement the freemarker.template.TemplateModelRoot interface and each subnode must implement another subinterface of freemarker.template.TemplateModel. What this means is that, when exposing an object graph, an adapter class will need to be written for each application class. String data can be exposed more easily, using the freemarker.template.SimpleScalar convenience class. The Guestbook sample application supplied with FreeMarker shows the use of adapters for each application class. There are 114 lines of code in adapter classes in this trivial application.

I've yet to see reflection prove a performance problem in this kind of situation, so I think that forcing such additional work on application developers to avoid using reflection in a framework is a poor design trade-off. However, not everyone agrees: see http://www.javaworld.com/jw-01-2001/jw-0119-freemarker.html for an article praising FreeMarker's design. The FreeMarker download includes separate packages that enable FreeMarker templates to access XML documents and JavaBeans using reflection, like templates in other products.

FreeMarker is also open source, and is published under the Gnu GPL. It is available at http://freemarker.sourceforge.net/.



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net