OpenACS Templates

Reuven explains how OpenACS templates collect and return data and perform automatic error checking.

Over the last few months, we've looked at the Open Architecture Community System, an open-source toolkit for creating community web sites. Last month, we even looked at how we can create a simple application package using the ArsDigita Package Manager (APM).

But at its heart, web development is all about receiving inputs in HTTP GET and POST requests and about producing pages of HTML in response to those requests. Each web development toolkit has its own set of templates, and each type of template has its own personality and quirks.

This month, we take a closer look at the OpenACS templating system, which is similar in some ways to Zope Page Templates (ZPT). The OpenACS templates are rather sophisticated in the way they collect and return data and make it possible to perform many types of automatic error checking that would otherwise be tedious or simply ignored.

OpenACS Templates

Older versions of OpenACS used a templating system known as AOLserver Dynamic Pages (ADPs), similar to JSP, ASP or PHP. ADPs could contain Tcl code, thanks to the multithreaded Tcl interpreter running inside of AOLserver, the HTTP server that powers OpenACS. However, ADP had a number of problems. Each Tcl block was evaluated independently, making it difficult to have conditional code inside of a template. There was no standard way to ensure that ADPs were passed required parameters to give parameters optional values. And of course, the troubles really began when developers and designers needed to work on the same file. Moreover, much of OpenACS was written in simple .tcl files, which can be quite daunting for a nonprogrammer.

The programmers at ArsDigita, whose code lives on in the OpenACS Project, decided that a paradigm shift was in order. No longer would pages be invoked with their familiar .html and .adp suffixes; instead, they would be called without a suffix at all.

This is possible because of AOLserver's willingness to search, in order, for an appropriate page. Given the URL /foo, AOLserver will first look for /foo.tcl, then for /foo.adp and finally for /foo.html. (This configuration setting can be changed in the nsd.tcl configuration file that typically is located in /usr/local/aolserver.)

The OpenACS templating system relies on this fact to split the work between two different files. In general, the output generated by an HTTP request has to go through two different files. The .tcl file executes first, performing database queries and setting variables. Its final line is typically going to be ad_return_template, a Tcl procedure that then invokes the companion .adp page. The ADP can retrieve the variables as data sources.

Because the .tcl and .adp files are supposed to be developed by separate people, it's natural to expect them to drift apart or have compatibility issues. The ArsDigita engineers avoided this problem by setting up a “page contract”, meaning a list of HTTP parameters that the .tcl file expects to receive, and then a list of Tcl variables (known as data sources) that will be available to the .adp page in its display.

Data Sources

Data sources are simply Tcl variables by another name. Inside of an .adp page, you specify a data source like @this@, with @ signs around the name. If the data source has not been defined, the template will exit with a Tcl stack trace, complaining of an unknown variable.

Data sources can be placed anywhere in a file. Their values are substituted in place of those on the HTML page before the HTML is sent to the user's browser, which means that data sources can define not only text, but also image names and stylesheet attributes.

For example, here is a simple OpenACS template that displays the user's first name in a first-level headline:

    <p>That's you, isn't it?</p>

The master tags indicate that the page in question is not complete HTML output, but rather is meant to be inserted inside of the local master (i.e., a template pair named master.tcl/master.adp). The local master, in turn, is wrapped inside of the site's default master (normally in a template pair named default-master.tcl and default-master.adp, but this is configurable using parameters). Thus, the resulting page consists of:

default master top
    local master top
        our page
    local master bottom
default master bottom
In this way, you can create sites that have a unified look and feel, with common headers and footers, such as menubars and contact information. The notion of masters and default masters is similar in many ways to autohandlers in the Perl-based HTML::Mason templating system.

This is all well and good, but where is @first_name@ defined? It is defined in the companion .tcl file. But it's not enough for the .tcl file to set the first_name variable. It also must mark the variable for export as a data source by naming it explicitly.

.tcl pages name their inputs and outputs in arguments to the ad_page_contract procedure, which normally executes at the top of a page. ad_page_contract is a powerful mechanism that lets us create pages that expect to receive certain inputs, which in turn promise to produce certain outputs. A call to ad_page_contract can range from extremely simple to extremely complex, depending on the needs of the .adp template page. For example, a .tcl page that sets the user's first name to a dummy value and then exports it to the .adp page could look like:

ad_page_contract {
    Comments and CVS information go here.
} {
} -properties {
set first_name "Dummy first name"

The call to ad_page_contract tells the templating system that the variable first_name will be exported. We then set the variable's value and finally pass those values to the template with ad_return_template. (For unfortunate historical reasons, data sources are passed in the -properties parameter, rather than something with a more informative name.)

We can pass multiple variables to the template by naming additional variables in ad_page_contract:

ad_page_contract {
    Comments and CVS information go here.
} {
} -properties {
set first_name "FirstName"
set last_name "LastName"

Geek Guide
The DevOps Toolbox

Tools and Technologies for Scale and Reliability
by Linux Journal Editor Bill Childers

Get your free copy today

Sponsored by IBM

8 Signs You're Beyond Cron

Scheduling Crontabs With an Enterprise Scheduler
On Demand
Moderated by Linux Journal Contributor Mike Diehl

Sign up and watch now

Sponsored by Skybot