15.4 WebMacro Templates

Java Servlet Programming, 2nd Edition > 15. WebMacro > 15.4 WebMacro Templates

 
< BACKCONTINUE >

15.4 WebMacro Templates

To demonstrate the context tools and directives available to WebMacro templates, Example 15-6 shows a simple template that prints information from the request.

Example 15-6. Snooping the Request with WebMacro
## snoop.wm #set $Response.ContentType = "text/html" <HTML><HEAD><TITLE>Let's Snoop!</TITLE></HEAD> <BODY> ## A snoop template to get comfortable with WebMacro <H1>Miscellaneous Info</H1> QueryString: $Request.QueryString<BR> RemoteUser: $Request.RemoteUser<BR> ## WebMacro does not yet recognize isXXX() properties; must use a method call ## It doesn't currently have elseif either (it's being added) #if ($Request.isRequestedSessionIdFromCookie())  {   You're in a session thanks to cookies! } #else {   #if ($Request.isRequestedSessionIdFromURL()) {     You're in a session thanks to URL rewriting!   }   #else {     You're not in a session, poor guy.   } } <H1>Parameter Info</H1> #foreach $paramName in $Request.ParameterNames {   $paramName: $Request.getParameter($paramName) <BR> } <H1>Header Info</H1> #foreach $headerName in $Request.HeaderNames {   $headerName: $Request.getHeader($headerName) <BR> } <H1>Cookie Info</H1> #foreach $cookie in $Request.Cookies {   $cookie.Name: $cookie.Value <BR> } </BODY></HTML>

Figure 15-2 shows a screen shot.

Figure 15-2. Snooping with WebMacro

This template demonstrates the #set directive to set the content type of the response. It uses the #if and #else directives to determine if the client joined a session using a cookie or URL rewriting or isn't part of the session, and it uses the #foreach directive to loop over the parameter, header, and cookie values present in the request.

Some tricks to notice: first, a bean accessor method following the naming pattern isProperty( ) isn't located automatically by WebMacro and must be called explicitly through method invocation. Second, there's no #elseif directive currently, so an if/elseif/else construct has to be done through nesting.

15.4.1 A Reusable MacroView Servlet

The template from Example 15-6 can be considered "standalone" because it uses no servlet-provided variables. Standalone templates can't be invoked directly and require a servlet to call them, but because the template has no special needs, that servlet can be a generic and reusable MacroView servlet, as shown in Example 15-7.

Example 15-7. A Generically Reusable WebMacro Servlet
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.webmacro.*; import org.webmacro.servlet.*; import org.webmacro.engine.*; import org.webmacro.broker.*; // Extending com.oreilly.servlet.CacheHttpServlet can improve response time public class MacroView extends HttpServlet {   WebMacro wm;  // WebMacro main hook   public void init() throws ServletException {     try {       wm = new WM();     }     catch (InitException e) {       throw new ServletException(e);     }   }   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     FastWriter out = new FastWriter(res.getOutputStream(),                                     res.getCharacterEncoding());     // The template name comes as extra path info     //   /servlet/MacroView/templ.wm     // or as servlet path via a *.wm rule     //   /templ.wm     String template = req.getPathInfo();     if (template == null) {       template = req.getServletPath();       template = template.substring(1);  // cut off leading "/"     }     // If template is still null, we have a problem     if (template == null) {       throw new ServletException(         "No template specified as extra path info or servlet path");     }     try {       Template tmpl = wm.getTemplate(template);       WebContext context = wm.getWebContext(req, res);       tmpl.write(out, context);     }     catch (WebMacroException e) {       throw new ServletException(e);     }     finally {       out.flush();     }   }   public void destroy() {     super.destroy();     if (wm != null) wm.destroy();   } }

This servlet calls on whichever template name was passed as extra path info, or if there's no extra path info, then it calls on the template name pointed to by the servlet path (through a file extension match). It can be convenient to register this servlet to handle all *.wm requests using the web.xml snippet in Example 15-8. This allows WebMacro template files to appear to be requested directly using URLs like /snoop.wm or /webmacro/snoop.wm, while in reality the MacroView servlet handles the processing behind the scenes.

Example 15-8. Registering MacroView to Handle *.wm
    <servlet>         <servlet-name>             mv         </servlet-name>         <servlet-class>             MacroView         </servlet-class>     </servlet>     <servlet-mapping>         <servlet-name>             mv         </servlet-name>         <url-pattern>             *.wm         </url-pattern>     </servlet-mapping>

You may find it useful to enhance the MacroView servlet to perform some standard business logic on each request and perhaps make a set of common objects available in the context for all system templates. A servlet like this, combined with the context tools discussed later, lets WebMacro templates operate with a pull model similar to Tea (and in fact that's how AltaVista uses WebMacro).

15.4.2 Template Processing

WebMacro does quite a lot of template parsing work behind the scenes that programmers and designers don't generally need to think about but whose mechanisms should be understood to make the most of the tool. WebMacro parses templates on their first use and after that stores a representation of the template suitable in memory for fast execution. WebMacro automatically reloads and reparses the template content after template file changes but for efficiency checks timestamps only after a timeout period, specified as the TemplateExpireTime in WebMacro.properties. By default the timeout is milliseconds so that timestamps are checked on every request. That's convenient for development, but make sure you increase the timeout for production use. For power users, template objects have a parse( ) method that forces a load and parse. You can use this method to parse all your templates at startup or to force an early reparse if you know a template has changed.

When templates have errors, various things can occur. If a referenced variable or property has a null value or doesn't exist, WebMacro treats that failed substitution as a noncatastrophic error. WebMacro generates the page as best it can but writes a WARN message to the log and in the generated page places an HTML/XML comment at the location of the error (this approach has some shortcomings if the generated page is not HTML or XML):

<!-- warning: attempt to write out undefined variable Request.ContentType: java.lang.NullPointerException -->.

If a template has a syntax error, WebMacro does treat that as a catastrophic failure and writes an ERROR message to the log and in the generated page displays an error description.[4] For certain types of errors, such as a template not being found by a servlet, WebMacro has the notion of a default error template to display, configured with the ErrorTemplate property in WebMacro.properties.

[4] There's a bug in WebMacro 0.94 (the version against which the code in this chapter was tested) where a template syntax error can cause WebMacro to generate an empty page instead of a page with an error description. No doubt this bug will be fixed in later versions.

Of course, most of the error handling within a WebMacro site dealing with invalid parameters, crashed databases, missing files, and all the other errors that should be checked before control passes to the template should occur in servlet code. WebMacro works well for this. A servlet can use a set of standard WebMacro templates to display these error cases, choosing which template to pass control to and what to include in the context depending on the error. For example, if a database error occurred, control could be rerouted to a sqlException.wm file along with the exception stack trace for display.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

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