How WebMacro Works

BACK | UP | NEXT

Installation Issues

Consult the README.html that ships with WebMacro, but the main things you have to get right are:
  • Install a Java Virtual Machine and a Servlet engine
  • Put webmacro.jar somewhere on your classpath
  • Put your servlet engine's .jar file on your classpath
  • Make sure WebMacro.properties is on your classpath as well
  • Edit WebMacro.properties setting your TemplatePath correctly

Introspection Rules

WebMacro follows the JavaBeans specification when performing class analysis, but also extends that specification.

JavaBeans is essentially a set of conding conventions for how to name accessor methods. If you follow those conventions then lots of tools, including WebMacro, will be able to analyze your class to learn what properties it has.

Here are examples of the properties that WebMacro can find:

When resolving $foo.Bar.Baz WebMacro can find:

  • foo.Bar.Baz -- just field names
  • foo.Bar.getBaz() -- a field and a JavaBeans accessor
  • foo.getBar().getBaz() -- simple JavaBeans accessors
  • foo.get("Bar").getBaz() -- hashtable lookup & accessor
  • foo.getBar("Baz") -- Baz is a named property of Bar
In the previous example, using #foreach, WebMacro needed to extract some kind of Iterator object from $Results. It can do that in any of these ways:
  • results[] -- results is an array already
  • results is already a Java2 Iterator
  • results is already a Java1 Enumeration
  • results.iterator() returns a Java2 Iterator (any Java2 collection)
  • results.elements() returns a Java1 Enumeration (Vector, Hashtable)
In cases where WebMacro needs to set a property, say $foo.Bar.Baz, it can find methods like these:
  • foo.Bar.Baz = value -- all fields
  • foo.Bar.setBaz(value) -- get a field and simple set accessor
  • foo.getBar().setBaz(value) -- get accessor and set accessor
  • foo.getBar().put("Baz", value) -- getBar() returns a hashtable?
  • foo.setBar("Baz", value) -- eg: response.setHeader(header,value)
NOTE: WebMacro can only access public fields and methods. The Java security API prevents WebMacro (or any other package) from gaining access to the private, protected, or package protected data of your objects. If you want WebMacro to see your method, you must make a public method.

Round bracket hack

Template writers may need to access data from a Java object which does not follow the Java beans spec, and does not follow any of the common extensions listed above that WebMacro can introspect.

In these cases you can explicitly name a Java method in a WebMacro template using the round bracket hack:

   $foo.name()
   $bar.loadValue(10,$arg1,true)
In this case $foo has a badly named accessor: name() should have been called getName(). On the other hand, $bar has a loadValue method which cannot easily be translated to a Java Bean method: it takes three odd arguments.

I call this the round bracket hack because any use of this syntax implies that the template author has some knowledge of the exact Java class which implements $foo and $bar. If instead you could have written $foo.Name the programmer could have provided either a hashtable, or a method with public fields, or a method with public accessors. Since the template writer actually refers to the method by name the programmer winds up being restricted by the template author.

A better solution would be to wrap the non-bean class in a JavaBean interface. In the future, when WebMacro's introspector is still more powerfult han iti s now, the round bracket hack may be deprecated and eventually removed.

Concurrency Model: Context-per-thread

Multiple threads can execute a WebMacro template simultaneously: the template is immutable. Once it is loaded and parsed it doesn't change.

Each thread should have its own Context. Think of a Context as the place where each Thread keeps its local data. Since each Context is accessible to only one Thread, it does not need to be locked.

Thus, WebMacro avoid many locks: Templates are not locked because they are immutable. Contexts are not locked because they are accessed by only a single thread each.

You will need synchronization locks in a WebMacro based servlet only when you explicitly share data between multiple threads.

Performance

WebMacro does a lot of work in order to generate your page, so you might wonder whether it's efficient. Here are some answers:
  • Templates are compiled for efficiency. WebMacro runs a two-phase compile which optomizes out some static content. Unicode character encoding/decoding is done at template compile time and cached for re-use on each request.

  • Class analysis is cached for efficiency. Analyzing Java classes is very expensive so WebMacro doesn't do that on every request. The first time a class is analyzed WebMacro caches that data for later re-use. It turns out that invoking a reflected method is quite fast, so if you can avoid the expense of the analysis there isn't that much of a hit.

  • Lock-free design. There are very few synchronization locks in WebMacro, which helps concurrency a lot. Templates are immutable and Contexts are accessed one-per-thread. There are a few locks around various caches but they are constructed to minimize the time a thread must spend inside the monitor, the result being that a high degree of concurrency is possible.
It turns out that for typical applications the cost of your back-end data source will swamp the cost of WebMacro. Generating a page is a fairly efficient operation. You will need to concentrate on optomizing the portions of your application which perform I/O and other more expensive operations--WebMacro will account for only a fraction of the cost of the page.

Extending the Framework

WebMacro loads almost all of its implementation from a configuration file at runtime. You can easily override, extend, or change its behavior by naming your own files in the configuration file instead of the defaults WebMacro ships with.

Here are some of the things you can plug in via configuration file:

  • New directives for the script language (pluggable directives)
  • What default variables are available in every template (Tools)
  • Where templates are loaded from (template path)
  • How and when templates are loaded (template provider)
  • How long and whether templates are cached
  • How the WebMacro language itself is parsed (pluggable parser)
This is what makes WebMacro an extensible framework: almost every aspect of its behavior can be easily overridden.

As the developer of an application framework you can take advantage of these features to customize WebMacro to your particular needs.


BACK | UP | NEXT