type safe templating

Previous Tutorial contents  

Jamon Tutorial - 11. Jamon Context: Providing data to all templates at once

All of the examples of dynamic content in templates that we've seen up until now have involved data that is passed in explicitely to a template. However, certain kinds of information don't "want" to be passed around as arguments from template to template. For example, suppose you have a utility template to generate your site's logo. Since some pages on your site might be accessed with either the http: or https: protocols, you want your image template to be able to generate either insecure or secure image urls, depending on the way the page is being accessed. As a first stab at this, you might write a template looking something like:
<%args>
  boolean secure;
</%args>
<img href="http<%if secure %>s</%if>://myhost.myorg.com/logo.jpg"/>
Unfortunately, now every component calling this template must be able to tell it whether the page is secure or not. If your site is well factored, you will likely have components calling those components as well, and all of them will need to know about security.

A better solution is to keep track of whether or not the page is secure by using the jamonContext variable. This is a special variable which can be made available to every template in your site, and will automatically be passed between them. To use jamonContext, you first must declare it's type. Since the type will need to be the same accross a number of templates, rather than declaring it in the body of a particular template (or requiring every template to declare it), the type is declared by setting the org.jamon.contextType property in a special file named jamon.properties; placing this in your templates directory will give every template a jamonContext variable of the specified type. The proxy classes will get an additional method, setJamonContext() which you can use to set the context.

An Example

  1. Create a java class for context, MyContext.java:
    public class MyContext {
      private boolean secure;
    
      public boolean isSecure() {
        return secure;
      }
      
      public void setSecure(boolean secure) {
        this.secure = secure; 
      }
    }
    
  2. Create a file jamon.properties in your template directory:
    org.jamon.contextType = MyContext
    
  3. Create Logo.jamon:
    <img href="http<%if jamonContext.isSecure() %>s</%if>://logo.jpg"/>
    
  4. Create WelcomeTemlpate.jamon:
    <html>
      <body>
        <& Logo &> Welcome to our site!
      </body>
    </html>
    
  5. Call this template from the Java class, WelcomeTut11.java:
    import java.io.OutputStreamWriter;
    
    public class WelcomeTut11 {
      public static void main(String[] argv) throws Exception {
        MyContext context = new MyContext();
        context.setSecure(true);
        new WelcomeTemplate()
          .setJamonContext(context)
          .render(new OutputStreamWriter(System.out));
      }
    }
    
  6. The output should be
    <html>
      <body>
        <img href="https://logo.jpg"/> Welcome to our site!
      </body>
    </html>

Best Practices

For those coming from the JSP world, it might be tempting to use the jamonContext in the same way as attributes on the HTTPServletRequest instance are used in JSP pages. As a general rule, it's best passing data via <%args> blocks; jamonContext should be reserved for exceptional cases such as the one described above, or locale information, which span the context of an entire application.

For writers of jamon template libraries who wish to make use of the jamonContext variable, it is strongly encouraged that they choose a Java interface for the context variable type. This will clients to provide an implementation of that interface which also provides other data needed for client-specific applications.

Previous Tutorial contents