Technology Investigation Outline - WebMacro
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:
- Broad overview of WebMacro operation
- Development steps for a form
- Comparison of WebMacro (and template engines in general) to JavaServer Page technology
- Consideration of object frameworks based on WebMacro
- 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, 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:
- A template language for web page designers to use, into which they can substitute values from a web program
- 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:
- A WebMacro-based servlet receives a request from a user.
- The servlet processes the request, which may involve interaction with JavaBeans and other classes on the server.
- 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.
- 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.
|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.
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:
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
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:
#foreach $customer in $customerList
<li> $customer.name owes $customer.owing
Simple conditionals are also supported. In the current version developers can only test whether something is defined or not:
Yes we have variable: $variable
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--"
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
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
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
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
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
34 inputString = (String) context.getForm("inputString");
36 catch (Exception e)
40 if (inputString == null)
42 inputString = "";
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
51 return (Template) context.getBroker().getValue(TemplateProvider.TYPE,
54 catch (Exception e)
56 throw new HandlerException("Could not locate template: "
57 + templateName);
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
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
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)
18 <H2>URLEncodingWMPage Output</H2>
19 <P>Input string: $Form.inputString</P>
20 <P>URL Encoded: $EncodedString</P>
21 <P> </P>
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">
30 <INPUT TYPE="RESET">
31 <INPUT TYPE="SUBMIT">
33 <P> </P>
34 <P><SMALL><I>Script: URLEncodingWMPage 0.1 by Bruno Andrighetto<BR>
35 Date: $DateString</I></SMALL></P>
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.
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.
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.
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.
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.
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.
- WebMacro helps enforce the MVC framework, in this case:
- Model = CurrentDateTime.java, BirthdayNotices.java, Birthday.java
- View = intranet.wm
- Controller = IntranetWMPage.java
- The JavaBeans (Model classes) have been reused, without modification, from the JSP version.
Date: Friday, April 28, 2000 10:27 AM