type safe templating

Previous Tutorial contents Next

Jamon Tutorial - 10. Template Inheritance: Overriding Inherited Methods/Subtemplates

As explained in the section on TutorialSample7.html, a subtemplate can either be private or protected. Subtemplates defined with the <%def subTempName> ... </%def> tag are private and can be accessed only within the template that defined the subtemplate.

Subtemplates defined with the <%method subTempName> ... </%method> tag, however, are protected and can be accessed by templates that inherit from the template with the subtemplate definition. To invoke a protected subtemplate defined in a parent, a child template simply invokes it like any other subtemplate

<& subTempName &>
Usually, however, it is the parent template that invokes the subtemplate, and the parent makes the template protected so that the child can override it. For example, the template InheritanceParentProtected.jamon declares a title subtemplate for the expressed purpose of allowing the child template to override the subtemplate in order to replace the title.
<%abstract>
<%args>
  User2 userAccount;
</%args>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title><& title; name = userAccount.getName() &></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>

<%method title>
  <%args>
    String name;
  </%args>
    Jamon News for <% name %>
</%method>

The template that derives this template would override the title subtemplate by using the <%override tutorialName> ... </%override> tag.

<%override tutorialName>
  <%xargs>
    name;
  </%xargs>
  Jamon Specials for <% name %>
</%override>
Overridden methods take the same arguments as the method they override, although, as with template inheritance, only those arguments declared in an <%xargs> ... </%xargs> block will be visible within the body of the override. Also, as with template inheritance, only the names of the arguments are listed within the <%xargs> ... </%xargs> tag, because the types of the arguments are declared in the parent template's definition.

The template InheritanceChildProtected.jamon, below, extends InheritanceParentProtected.jamon and overrides the subtemplate title. By overriding the title method InheritanceChildProtected replaces the title that the parent template generates.

<%extends InheritanceParentProtected>
<%args>
  String special;
</%args>
<%xargs>
  userAccount;
</%xargs>

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

<%override title>
  <%xargs>
    name;
  </%xargs>
  Jamon Specials for <% name %>
</%override>

The class User2.java takes advantage of the fact that the InheritanceParentProtected supports inheritance by delegating the choice of which derived template to invoke to a separate method and then simply calling the render() method on the object returned. The top level controller simply has to provide the output Writer and the arguments required by the parent template, InheritanceParentProtected, while the delegated method selects the actual template instance and provides the arguments required by that instance.

import java.io.OutputStreamWriter;

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

  public User2(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 {
    User2[] users = new User2[2];
    users[0] = new User2("John Public", false);
    users[1] = new User2("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])
        .render(new OutputStreamWriter(System.out), users[i]);
    }
  }

  /** Chooses the correct derived template to invoke and calls
   *  <code>makeParentRenderer()</code> on that instance.
   *
   *  @param templateName the key name of the template to create
   *  @return the <code>ParentRenderer</code> of the derived template
   */
  private static InheritanceParentProtected.ParentRenderer
    processUser(String templateName) {
    // the default template, the special of the week
    if (templateName == null || "special".equalsIgnoreCase(templateName))
    {
      return new InheritanceChildProtected()
        .makeParentRenderer("Jamon free this week only!");
    } else {
      // process other derived templates here
      return null;
    }
  }
}
The result of executing this class and template is below.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Jamon Specials for John Public
</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 Specials for John Rockerfeller
</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