type safe templating

Previous Tutorial contents Next

Jamon Tutorial - 9. Template Inheritance: Composing Template Output

Jamon template inheritance allows a template to declare that it can include the output of a child template that extends it. (There are other benefits of inheritence as well, which will be explained in the next tutorial section.)

The benefits of template inclusion are obvious: a containing template, for example, can set up the header, footer, and navigation bar of a web page while the included template can provide the body of the page. Template inheritance makes this inclusion easy: a parent template can set up the page layout while the child template simply declares that it extends the parent in order to have its output included by the parent.

For a template to declare that it supports inheritance it must specify the tag

 <%abstract>
Then, where the parent template wants to include the output of a derived, or child, template, it must specify the tag
 <&* CHILD &>

For example, the template InheritanceParent.jamon, shown below, declares the <& *CHILD &> where it wants to include the child template's output. The parent template takes care of the HTML header as well as the page's header banner while the child template simply fills in the body.

<%abstract>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Jamon Documentation</title>
  </head>
  <body>
    <%doc> could include a navigation bar here </%doc>
    <h1>Jamon</h1>
    <h3>a typed template engine for Java</h3>
    <hr>

    <& *CHILD &>

    <%doc> could also include a footer here</%doc>
  </body>
</html>

The child template declares that it extends the parent template by including the tag

<%extends InheritanceParent>
If the parent template is in a different directory, then the extends tag must specify the path to the parent template.
<%extends ../InheritanceParent>
The example template below, InheritanceChild.jamon extends InheritanceTemplate and provides subject text that is included in the output of the parent template.
<%extends InheritanceParent>

<h2>Inheritance Documentation</h2>
To declare that a template extends a parent template, it must include
the <code>&lt;%extends></code> tag.
This template would be invoked from Java with the class InheritanceSimpleTut9.java
import java.io.OutputStreamWriter;

public class InheritanceSimpleTut9
{
  public static void main(String[] args) throws Exception {
    new InheritanceChild().render(new OutputStreamWriter(System.out));
  }
}
The output from the template is
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Jamon Documentation</title>
  </head>
  <body>
    <h1>Jamon</h1>
    <h3>a typed template engine for Java</h3>
    <hr>

    <h2>Inheritance Documentation</h2>
To declare that a template extends a parent template, it must include
the <code>&lt;%extends></code> tag.


    </body>
</html>

Inheritance with template arguments

Both the parent and child templates may take arguments. To specify arguments, the parent and child templates simply include a <%args> ... </%args> tag.

By default, arguments in the parent template are not visible to the child template. They can be made visible to code in the child template by declaring them in <%xargs> ... </%xargs> blocks.

For example, consider the parent template InheritanceParentWArgs.jamon. It defines arguments userAccount and title.

<%abstract>
<%args>
  User userAccount;
  String title = "";
</%args>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title><% title %></title>
  </head>
  <body>
    <%doc> could include a navigation bar here </%doc>
    <h1>Jamon</h1>
    <h3>a typed template engine for Java</h3>
    <hr>
<%if userAccount.isAuthorized() %>
  <& *CHILD &>
<%else>
  <em>Not authorized to view this page.</em>
</%if>

    <%doc> could also include a footer here</%doc>
  </body>
</html>
The child template can only access these arguments by including

<%xargs>
  userAccount;
  title = "special of the week";
</%xargs>

Notice that only the name of the arguments should be listed. This is because the types of the arguments are already specified in the parent class. Also note, however, that any optional arguments can have their default values redefined in the child template.

A complete example of a child template, InheritanceChildWArgs.jamon, is below.

<%extends InheritanceParentWArgs>
<%args>
  String special;
</%args>
<%xargs>
  userAccount;
  title = "special of the week";
</%xargs>

<h2>Weekly Special</h2>
<% userAccount == null ? "You" : (userAccount.getName() + ", you") %>\
 qualify for the special of the week!
<blink><% special %></blink>

Invoking a derived template

The two choices for invoking a derived template are
  1. the Java code can call the render() method on the derived template and provide all the arguments that are required by the child template as well as all arguments required by the parent template, or
  2. the code may also call the makeParentRenderer() method on the derived template, provide the arguments required by the child template, and then call render on the InheritanceParentWArgs.ParentRenderer object returned by makeParentRenderer() method and provide the arguments required by the parent template.
The second approach allows the developer to separate the handling of the derived template from the parent template. This allows the generic processing of the parent template to be handled in a controller object while the specific processing of the child templates can be handled in separate Java classes.

The class User.java implements invoking the child template through the second approach described above.

import java.io.OutputStreamWriter;

public class User
{
  private String name;
  private boolean authorized;

  public User(String p_name, boolean p_authorized) {
    name = p_name;
    authorized = p_authorized;
  }

  public String getName() { return name; }
  public boolean isAuthorized() { return authorized; }

  public static void main(String[] args) throws Exception {
    User[] users = new User[2];
    users[0] = new User("John Public", false);
    users[1] = new User("John Rockerfeller", true);

    for (int i=0; i<users.length; i++) {
      // call render() on the parent template and provide arguments
      processUser(args.length == 0 ? null : args[0])
        .setTitle("Jamon News")  // set optional argument in parent
        .render(new OutputStreamWriter(System.out), users[i]);
    }
  }

  private static InheritanceParentWArgs.ParentRenderer
    processUser(String templateName) {
    // the default template, the special of the week
    if (templateName == null || "special".equalsIgnoreCase(templateName)) {
      return new InheritanceChildWArgs()
        .makeParentRenderer("Jamon free this week only!");
    } else {
      // process other derived templates here
      return null;
    }
  }
}

The output from the template is

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Jamon News</title>
  </head>
  <body>
    <h1>Jamon</h1>
    <h3>a typed template engine for Java</h3>
    <hr>

  <em>Not authorized to view this page.</em>


    </body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Jamon News</title>
  </head>
  <body>
    <h1>Jamon</h1>
    <h3>a typed template engine for Java</h3>
    <hr>

  <h2>Weekly Special</h2>
John Rockerfeller, you qualify for the special of the week!
<blink>Jamon free this week only!</blink>



    </body>
</html>

Previous Tutorial contents Next