15.1 The WebMacro Framework

Java Servlet Programming, 2nd Edition > 15. WebMacro > 15.1 The WebMacro Framework

 
< BACKCONTINUE >

15.1 The WebMacro Framework

The WebMacro framework works like this: a servlet receives a client request, the servlet does the business logic required to handle the request (likely using supporting classes or components such as EJBs), and the servlet creates a context object full of "answer objects" containing the results of the business logic that should be displayed to the client. The servlet then selects a template file (perhaps based on the business logic results) and pushes the answer objects through the template file generating content for the client.

A Java programmer creates the servlet and the business logic in pure Java, and a template engineer creates the template file for rendering. The template consists of HTML or XML content filled with a simple substitution syntax and minor scripting abilities. The syntax is HTML and XML-editor friendly, explicitly avoiding the use of angle brackets to ensure HTML and XML parsers don't get confused. The programmer provides to the template engineer a list of variables that will be present, as well as a list of the properties and methods of those variables.

The model has some similarity to the TeaServlet architecture, with the difference that WebMacro by default uses more of a servlet-driven push model, provides no sandboxing of the template, and uses a more simplified scripting syntax. We suspect that WebMacro has an advantage over Tea for highly functional web applications that have a completion point, and Tea has an advantage over WebMacro for sites that continuously add new template content and need template sandboxing and less programmer involvement.

15.1.1 Saying Hello with WebMacro

Example 15-1 demonstrates a simple servlet making use of the WebMacro templating system. Example 15-2 shows the hello.wm template file. Together they print the current date and time. We'll talk about where to place the files in the next section.

Example 15-1. A Simple Servlet to Drive the Hello Template
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import org.webmacro.*; import org.webmacro.servlet.*; public class WMHello extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     FastWriter out = new FastWriter(res.getOutputStream(),                                     res.getCharacterEncoding());     try {       WebMacro wm = new WM(); // optionally WM("/path/to/config/file")       Context c = wm.getWebContext(req, res);       c.put("date", new Date());       Template tmpl = wm.getTemplate("hello.wm");       tmpl.write(out, c);       out.flush();     }     catch (WebMacroException e) {       throw new ServletException(e);     }   } }
Example 15-2. A Simple Hello Template
## hello.wm #set $Response.ContentType = "text/html" <HTML><HEAD><TITLE>Testing WebMacro</TITLE></HEAD><BODY> Hello! <P> The current time is $date. <BR> (For you nerds, that's $date.Time milliseconds.) <P> </BODY></HTML>

Let's look first at the servlet. It's a normal servlet, extending HttpServlet and implementing the doGet( ) method. You'll notice right away that its logic is different. It retrieves a FastWriter instead of a normal PrintWriter. This allows special optimizations to avoid the cost of Unicode conversion for static content. It works like an ordinary writer with the improvement that WebMacro can push preencoded bytes through it and also call setAsciiHack(true) to gain speed when outputting Latin-1 or US-ASCII data. Just be aware that (at least currently) you must call the writer's flush( ) method to send the writer's buffered content to the client.

The code within the try block creates a new WebMacro object, to act as its primary hook into the WebMacro system. WebMacro is an interface, so the servlet actually constructs an instance of the concrete class WM that implements the WebMacro interface. The servlet then calls wm.getWebContext(req, res) to retrieve a WebContext in which to put answer objects to be passed to the template. The context operates like a Hashtable. It has a put(Object, Object) method which the servlet uses to place a Date object in the context under the name date. That object will then be available to the template executing within this context. For power users, it's interesting to note that the WebContext class extends Context, and the servlet could retrieve a non-web-aware Context by calling getContext( ). This comes in handy for some situations, such as for offline or nonservlet use.

To retrieve a template, the servlet calls wm.getTemplate("hello.wm") . The method accepts the name of the template to retrieve, including the file extension. A template can use any file extension, but most people use .wm by standard convention. With the template in hand, the servlet can call the template's write( ) method and pass as its parameters the FastWriter to write to and the WebContext full of answer objects. The output could be captured as a String also, using a Template's String evaluate(Context context) method.

If any method throws a WebMacroException , the servlet has been written to rethrow the exception wrapped within a ServletException. Nearly every WebMacro method can throw a WebMacroException or some subclass. The WM( ) constructor may throw an InitException if, for example, a required configuration file could not be found. The getTemplate( ) method may throw a NotFoundException if the template could not be found. And the write( ) method may throw a ContextException if the template required data that was missing from the context, and it may also throw an IOException if there was a problem writing to the client. All WebMacro-defined exceptions extend WebMacroException, a checked (nonruntime) exception, and it's common to catch and handle the generic exception class at the bottom of a doGet( ) method.

As another approach, you can write a WebMacro-enabled servlet by extending the org.webmacro.servlet.WMServlet superclass, a convenience demonstrated in Example 15-3.

Example 15-3. Another Approach to WebMacro Servlet Design
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import org.webmacro.*; import org.webmacro.servlet.*; public class WMServletHello extends WMServlet {   public Template handle(WebContext context) throws HandlerException {     try {       context.put("date", new Date());       return getTemplate("hello.wm");     }     catch (NotFoundException e) {       throw new HandlerException(e.getMessage());     }   } }

Following this style, a servlet extends WMServlet and implements a single handle( ) method. The superclass creates the WebMacro object automatically and passes WebContext in as a parameter. The servlet need only perform its business logic, fill the WebContext with appropriate answer objects, and return the template to use for page creation (or return null if the servlet handled the page creation itself internally). The methods start( ) and stop( ) may be implemented by the servlet as well, taking the place of a typical servlet's init( ) and destroy( ) methods. Should the HttpServletRequest and HttpServletResponse objects be needed, they can be retrieved from WebContext using the getRequest( ) and getResponse( ) methods.

Using the WMServlet superclass can be more convenient than handling the WebMacro objects manually. The price is a loss of power. You must use the manual approach to put two independent templates in a page, run the output through a filter such as a GZIPOutputStream, perform offline generation, differentiate between GET and POST requests, and determine whether the servlet has to extend another custom superclass.

Now let's take a look at the template. The template looks like a normal HTML page except for a little markup. In the body of the page we see the Date object, previously added to the context under the name date, has been included in the page using the syntax $date. We also see on the next line that the time property of the Date object (which holds the current time as a millisecond count) has been included using the syntax $date.Time. That's the simple substitution syntax used by WebMacro: $varname prints the variable value (converted to a String if necessary) and $varname.Property prints the property value. Property subproperties are also available using the syntax $varname.Property.Subproperty, and in fact far more than just bean properties can be accessed due to the advanced reflection work WebMacro performs, as we'll see later. For now, just remember that when accessing bean properties the property name must be capitalized.

Looking more at the template, at the beginning of the file there's a comment telling us the name of the file. Comments in WebMacro begin with ## and continue to the end of the line. Right below the comment there's a #set command, what WebMacro calls a directive. This sets the ContentType property on the Response object to the value "text/html", which is equivalent to calling response.setContentType("text/html"). The $Response variable represents the servlet response and, along with $Request, is implicitly made available in all WebContext objects. WebMacro has a handful of directives for handling variable manipulation, file inclusion, conditional logic, and looping. We'll look at these in more detail later.


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