subsection contents

Technology Investigation Outline - WebMacro

Introduction

The purpose of this document is to explore the capabilities of WebMacro in the context of developing web-based applications.

The document provides a broad overview of standard WebMacro technology, including:

  1. Broad overview of WebMacro operation
  2. Development steps for a form
  3. Comparison of WebMacro (and template engines in general) to JavaServer Page technology
  4. Consideration of object frameworks based on WebMacro
  5. Other issues, including software requirements

A list of related online resources is provided at the end of the document.

 

What is WebMacro?

WebMacro is a free Java servlet development framework, including a template language and extensible component model. It uses beans and introspection to make any Java object in your servlet accessible in your template.
WebMacro FAQ

WebMacro, like Sun's JavaServer page (JSP) technology, is an extension of the Java Servlet API. However, unlike JSPs which must be translated into servlet classes before being executed, WebMacro pages are essentially templates which are read in, parsed and displayed via the WebMacro template engine (*rewrite*).

The goal of WebMacro is to separate page design from the application code.

WebMacro is being developed by Semiotek Inc and is available for use under the GNU Public Licence (GPL). A less restrictive licence can be negotiated with the developers. More details regarding licensing are contained in the WebMacro Licensing document.

WebMacro has been designed to fit the biases of the developers (from WebMacro Readme document):

  • it is wrong to use markup for a scripting language
  • it is wrong to embed programs on a web page
  • it is wrong for web scripts to look like hard programming
  • that programming and graphics design are separate tasks

In keeping with its design philosophy, WebMacro provides two separate interfaces:

  1. A template language for web page designers to use, into which they can substitute values from a web program
  2. A library and framework for web based programming, for use by technical developers, which is independent of any layout or other graphical concerns

 

How WebMacro Works

WebMacro consists of an HTML template engine and a framework of back end servlet classes. WebMacro applications operate within the standard HTTP request/response paradigm.

In broad terms, a WebMacro application works as follows:

  1. A WebMacro-based servlet receives a request from a user.
  2. The servlet processes the request, which may involve interaction with JavaBeans and other classes on the server.
  3. The WebMacro template engine loads a template page, executing any WebMacro Script contained within it.
    Note that the first time a template is loaded, WebMacro engine parses it into an intermediate form for faster execution.
  4. The resultant HTML document is sent to the user's web browser.

WebMacro technology enforces the separation of page design and application logic. Therefore, any application based on WebMacro will require at least two source files: a WebMacro servlet and a WebMacro template. This contrasts with "pure" servlets which allow the development of servlets that contain the application logic and generate all the HTML markup. The WebMacro approach also contrasts with JSPs, which allow developers to embed Java code into pages alongside HTML markup.

The WebMacro philosophy promotes the Model-View-Controller (MVC) framework. This framework separates the model (or business logic) from the view logic in an application, with a controller managing the interaction between the model and the view. In the context of a Java-based web application, JavaBeans provide a natural mechanism for implementing the business logic. WebMacro templates can be used as the view component. And WebMacro servlets can implement the controller component. This is discussed in the WebMacro Framework Design Overview.

The diagram below shows how WebMacro technology can be used within an MVC framework.

WebMacro Access Model
MVC Framework using WebMacro

 

The WebMacro QuickStart document provides an overview of how to write WebMacro applications. The following section is based on information contained in that document. More comprehensive information is contained in the WebMacro API documentation and in the WebMacro Script article.

As mentioned earlier, a WebMacro application consists of at least two components: a WebMacro servlet and a WebMacro template.

WebMacro Servlets

The servlet component involves either implementing the org.webmacro.servlet.Handler interface, or else subclassing from org.webmacro.servlet.WMServlet. Since the latter is the preferred approach, this document will focus on that approach.

Template handle(WebContext) is the primary method that needs to be implemented by a subclass of WMServlet. Each connection to the server results in a call to the servlet's handle() method. When WebMacro calls the WMServlet.handle() method it will pass a WebContext object. This is basically a big Map which can be used to store other objects. The WebContext object also has a variety of helper objects within it which can be used to query things about the state of the application.

Any variable that placed into the WebContext is available as a local variable to the template. The WebContext is a JDK 1.2 style Map. Objects are placed into the WebContext by invoking the put() method. For example:

context.put("customer", customerObject);

The handle() method returns a Template object. It is the responsibility of the handle() method to select which template will be used to generate the HTML that is returned to the browser.

Templates use "Property Introspection" to access the data stored in the WebContext. WebMacro uses the introspection/reflection APIs to take a pretty deep look into the objects in the WebContext. The template language has access to the properties of the objects contained in the map.

For simple values, it will attempt this in two ways:

  • it will use the bean approach and look for public fields or appropriately named get/set methods
  • if it hasn't found a specific method, it will try and view the object as a collection and use put/get methods

If a list of objects is to be stored in the template there are several options. The property introspection method is capable of iterating through any of the following types:

  • an array
  • anything that has an elements() method that returns an Enumeration
  • anything that has an iterator() method that returns an Iterator

WebMacro Templates

Templates contain the output of the application. Each template represents a one page view in the system.

Any objects placed by the servlet in the WebContext can be accessed by the template. For example, if the servlet places an object called "customer" in the WebContext, the object's fields can be accessed as follows:

Customer $customer.name owes $customer.owing

It is possible to loop through list values that may be part of an object:

<ul>
#foreach $customer in $customerList
{
    <li> $customer.name owes $customer.owing
}
</ul>

Simple conditionals are also supported. In the current version developers can only test whether something is defined or not:

#if ($variable)
{
    Yes we have variable: $variable
}
#else
{
    Sorry, variable is not defined here
}

Other things that can be done using WebMacro Script in templates are:

  • #include "someUnparsedFile.txt"
  • #set $variable = value
  • #parse "includeSomeWebMacroTemplate.wm"
  • #include "$variableFile"
  • #use 'text' until "--The End--"

    Text here is not parsed by WebMacro, up until the line matching the supplied boundary. Use this to surround sensitive things like JavaScript, if it can conflict with WebMacro.
    --The End--

The WebMacro context includes a collection of convenient variables that can be accessed. For example

  • $Broker allows reading things from the ResourceBroker, an extensible resource manager which a programmer can plug components into on the back end
  • $CGI provides access to CGI-style variables
  • $Form provides access to FORM data
  • $Config provides access to properties in WebMacro.properties
  • $Cookie allows you to get and set cookies from the template
  • $Session allows you to get and set things in the JSDK session
  • $Request is the HTTP request (HttpServletRequest)
  • $Response is the HTTP response (HttpServletResponse)

An example application using WebMacro will be presented and described in the next section.

 

Developing a Form Using WebMacro

To demonstrate how to develop a form using WebMacro technology, the following example HTML template and Java program will be discussed. It's a rather simple application that prompts the user to enter a string, which is then encoded into a format that is URL-friendly.

The source code for the application logic of this example is provided in Listing 1: URLEncodingWMPage.java, while the view is given in Listing 2: URLEncodingWMPage.wm.

 

Listing 1: URLEncodingWMPage.java
     1       /**
     2   * Sample Java WebMacro Servlet
     3   * Name: URLEncodingWMPage.java
     4   * Purpose: Present user with a form for entering a single string.
     5   *          When form is submitted, contents of string are encoded as URL,
     6   *          which is then returned to the user.
     7   * @author: brunoa
     8   * Date created:  18 April 2000 14:45
     9   * Last modified: 19 April 2000 11:00
    10   */
       
    11  import java.net.*;
    12  import java.util.*;
    13  import org.webmacro.util.*;
    14  import org.webmacro.servlet.*;
    15  import org.webmacro.engine.*;
    16  import org.webmacro.resource.*;
       

    17  public class URLEncodingWMPage extends WMServlet
    18  {
    19     private String inputString;
    20     private String encodedString;
    21     private String dateString;
       
    22     private static Log log = new Log("urlencoder", "URLEncodingWMPage");
       
    23     public Template handle(WebContext context)
    24        throws HandlerException
    25     {
    26        Object output = new Object();
    27        String templateName = "URLEncodingWMPage.wm";
    28        Date date = new Date();
    29        dateString = date.toString();
    30        context.put("DateString", dateString);
       
    31        // get the user's input
    32        try
    33        {
    34           inputString = (String) context.getForm("inputString"); 
    35        }
    36        catch (Exception e)
    37        {
    38           log.exception(e);
    39        }
       
    40        if (inputString == null)
    41        {
    42           inputString = "";
    43        }
    44        context.put("InputString", inputString);
       
    45        // encode input string and store into context
    46        encodedString = URLEncoder.encode(inputString);
    47        context.put("EncodedString", encodedString);
       
    48        // return the template
    49        try
    50        {
    51           return (Template) context.getBroker().getValue(TemplateProvider.TYPE,
    52                templateName);
    53        }
    54        catch (Exception e)
    55        {
    56           throw new HandlerException("Could not locate template: " 
    57                                      + templateName);
    58        }
    59     }
       
    60  }  // URLEncodingWMPage

 

Listing 1 is the WebMacro servlet. A line-by-line description will now be provided.

Lines 1 to 10 contain some comments regarding the servlet.

Lines 11 to 16 contain statements to import the required packages:

  • java.net package is required for providing the URL-encoding functionality
  • java.util package is required for getting the date
  • org.webmacro.util package provides general utilities, such as the Log class
  • org.webmacro.servlet package provides the basic WebMacro servlet classes
  • org.webmacro.engine package provides the template rendering code
  • org.webmacro.resource package provides modules which are used to locate resources at runtime in the WebMacro system, such as the Template class

Line 17 declares that the URLEncodingWMPage class is a subclass of org.webmacro.servlet.WMServlet.

Lines 19 to 21 declare some private variables used within the servlet.

Line 22 declares and initialises a log for the servlet.

Lines 23 to 59 define the handle() method. It accepts a WebContext object, returns a Template object and throws a HandlerException if something goes astray.

Line 27 creates a String object, templateName, and initialises it to the name of the WebMacro template file.

Lines 28 to 30 get the current date as a string and place it into the context. This value will then be available for use within the template.

Lines 31 to 39 attempt to extract the user's input to the form:

Line 34 gets the value of the form field "inputString" and stores it in a private variable.

Line 38 logs any exception raised.

Lines 40 to 44 place the input string (or if there is none, an empty string) into the context.

Line 46 performs the URL-encoding upon the input string, using the java.net.URLEncoder class.

Line 47 places the encoded string into the context.

Lines 49 to 58 attempt to instantiate the Template object and return it:

Line 51 creates a Template object using the filename declared earlier.

Line 56 raises an exception if the template cannot be located.

 

Listing 2: URLEncodingWMPage.wm
     1       <!--
     2    -- Sample WebMacro Page
     3    -- Name: URLEncodingWMPage.wm
     4    -- Purpose: Present user with a form for entering a single string.
     5    --          When form is submitted, contents of string are encoded as URL,
     6    --          which is then returned to the user.
     7    -- @author: brunoa
     8    -- Date created:  18 April 2000 14:30
     9    -- Last modified: 19 April 2000 11:00
    10    -->
    11  <HTML>
    12  <HEAD><TITLE>URLEncodingWMPage Output</TITLE></HEAD>
    13  #set $Response.ContentType = "text/html"
    14  <BODY BGCOLOR="gainsboro">
    15  ## only want to display results if user entered some input
    16  #if ($Form.inputString)
    17  {
    18    <H2>URLEncodingWMPage Output</H2>
    19    <P>Input string: $Form.inputString</P>
    20    <P>URL Encoded: $EncodedString</P>
    21    <P>&nbsp;</P>
    22    <HR>
    23  }
    24  <!-- here's the actual form -->
    25  <H2>URLEncodingWMPage Form</H2>
    26  <FORM NAME="URLEncoder" ACTION="URLEncodingWMPage" METHOD="POST">
    27  <P>String to encode: 
    28  <INPUT TYPE="TEXT" NAME="inputString" VALUE="$InputString" SIZE="60">
    29  </P>
    30  <INPUT TYPE="RESET">
    31  <INPUT TYPE="SUBMIT">
    32  </FORM>
    33  <P>&nbsp;</P>
    34  <P><SMALL><I>Script: URLEncodingWMPage 0.1 by Bruno Andrighetto<BR>
    35  Date: $DateString</I></SMALL></P>
    36  </BODY>
    37  </HTML>

 

Listing 2 is the WebMacro template. A line-by-line description will now be provided.

Lines 1 to 10 contain some comments regarding the template.

Lines 11 to 12 contain HTML markup to begin the page and set the title.

Line 13 contains a WebMacro Script directive which sets the content type of the page to "text/html".

Line 14 starts the BODY section, setting the background colour.

Line 15 contains a WebMacro Script comment, which will not be visible in the generated web page.

Lines 16 to 23 contain a WebMacro Script conditional test and the HTML markup to generate if the condition is met:

Line 16 contains the #if directive to implement a test condition - is inputString defined in the form? (or: has the form been submitted?).

Lines 18 to 22 contain the HTML markup which is displayed if there is user input:

Line 19 contains the WebMacro Script term to insert the user's input from the context.

Line 20 contains the WebMacro Script term to insert the encoded value of the input string (from the context).

Lines 25 to 32 contain the HTML markup to display the form.

Lines 26 specifies the FORM tag. Note that the action attribute is set to the WebMacro servlet processing the form (i.e. URLEncodingWMPage - shown in Listing 1). Also, the form will be submitted using the POST method.

Line 28 contains a WebMacro Script term which sets the value of the form's inputString field (from the context).

Lines 33 to 37 contain the HTML markup to complete the page.

Line 35 contains a WebMacro Script term which inserts the current date from the context.

 

An example application which employs the MVC framework is provided in appendix 1.

 

Comparing WebMacro to JavaServer Pages

There a several major criticisms put forward regarding JavaServer page technology. In an article entitled The Problems with JSP, Jason Hunter identifies several issues, which WebMacro attempts to address:

  • It is too tempting to insert Java code in web pages
    WebMacro templates cannot contain Java code; rather WebMacro provides a simple script language aimed at page designers, with access to all of the underlying data that may be needed and enough power to lay it out in the desired way.
  • Some tasks can only be done using Java code within the page
    WebMacro Script contains built-in variables covering requests, responses, sessions and cookies without the need to resort to embedded Java.
  • Some simple tasks are made overly difficult
    WebMacro makes including headers and footers simple.
  • Looping is unnecessarily difficult
    WebMacro's looping directives are less clumsy than JSP-specific tags.
  • JSP page syntax errors are cryptic and often useless
    WebMacro errors are more meaningful, and a logging capability is provided.
  • Unless JSPs are pre-compiled, the web server will need to be equipped with a compiler
    WebMacro classes are compiled, and templates are pre-parsed the first time accessed.
  • JSPs consume both extra hard disk and extra memory space
    Template engines such as WebMacro don't need to duplicate the page data into a second file, so hard drive space is spared. Template engines also give the programmer full control over how templates are cached in memory.

WebMacro arguably achieves the separation of form and function using a simpler process and cleaner syntax.

However, template engines generally have some downsides:

  • No specification
    No specification exists for how a template engine should behave. This is far less important than with JSP because, unlike JSP, template engines demand nothing special of the web server -- any server supporting servlets supports template engines
  • Not widely known
    Template engines aren't widely known. JSP has had a tremendous amount of marketing and has gained terrific mind share. Using template engines is a relatively unknown alternative technique.
  • Not yet tuned
    Template engines have yet to be highly tuned. No performance numbers have been taken comparing template engine and JSP performance. Theoretically a well tuned implementations of a template engine should match a tuned implementation of JSP; however it is likely that, currently, JSP implementations are better tuned.

Reader reaction to Jason Hunter's article is also available online.

 

Developing Object Frameworks based on WebMacro

WebMacro templates contain most or all of the HTML markup, with a only dynamic content provided by servlets and/or back end components. It still may be beneficial to create a framework for generating basic HTML.

An object framework can also be developed to provide an abstraction over database connectivity. Assuming standard Java is used, it shouldn't be too difficult to develop object frameworks as JavaBeans which can be used in both JSP- and WebMacro-based architectures.

 

Other Relevant Issues

State, Authentication and Chunking

Since WebMacro technology is an extension of Java Servlets, all features available to servlet programmers are available in applications built using WebMacro. This includes the standard servlet session and cookie management capabilities.

Performance

Since WebMacro templates will need to be loaded and parsed before being presented, there will be a performance overhead the first time a page is accessed via the web server. Subsequent hits however will access the pre-parsed copy of the template.

Software Requirements

WebMacro is 100% pure Java, and is an extension of standard servlet technology. Once installed and configured, WebMacro should work with any Java-based servlet engine and/or Java-enabled web server.

Configuring WebMacro to work within a particular servlet environment may not always be straightforward. And the instructions provided were incomplete and contained some inaccuracies. A reasonable understanding of the servlet engine, web server and other components of the system environment is required in order to get WebMacro working properly.

A support Mailing List is available to help developers get WebMacro up and running, as well as to provide assistance with WebMacro development.

JDK Requirement

WebMacro as supplied is immediately usable with JDK 1.1.x. If the development and deployment environment is based on JDK 1.2, it will be necessary to unpack the sources and make a handful of simple modifications, before recompiling. The process is described in the WebMacro Readme document.

JavaScript Issue

There is a minor issue regarding the use of JavaScript within WebMacro templates. Specifically, developers need to be careful when using curly brackets to define blocks. The online documentation demonstrates how to safely incorporate JavaScript within templates.

Status of WebMacro

It should be noted that WebMacro is currently at version 0.89.1, and is still undergoing development. However it is a widely-used and well-respected template engine. Information about the current status of WebMacro is available online.

 

Online Resources

 

Appendix 1: Camtech Intranet front page

Camtech's Intranet front page has been re-written to utilise WebMacro technology and JavaBeans. The source code for the Java-specific components is provided here.

Notes:

  1. WebMacro helps enforce the MVC framework, in this case:
    • Model = CurrentDateTime.java, BirthdayNotices.java, Birthday.java
    • View = intranet.wm
    • Controller = IntranetWMPage.java
  2. The JavaBeans (Model classes) have been reused, without modification, from the JSP version.

 

Date: Friday, April 28, 2000 10:27 AM