Download / Getting Started

First of all it would be a good idea to download the current release. In the source jar you can find some working tests and examples. Also reading the web-site, then some Javadoc and perhaps some of the code will get you up and running. Especially the benchmark code may be helpful. Also take notice of my current plans for Toxic.

Table of Contents

Prerequisites

Java 7 Runtime / JDK
Toxic is written for the Java 7 platform.
SLF4J
Toxic uses simple logging facade for java as its logging backend.

License

This software is licensed under the MIT License (MIT).

Downloads

Toxic was originally hosted on berliOS developer site. As berliOS Developer site announced to close in 04/0214 the project moved to SourceForge. Or better: The SourceForge project, that was replicated from berliOS, was claimed by me. But currently there are no file releases. To follow recent development and download Toxic, just clone it from Gitorious.

As long as it is still running, you can also visit the old berliOS project site and download old versions of Toxic.

Fundamental Concepts

Toxic was not planned to be only a Java template engine but started based on my conviction that a template system consists of only the following:

  • The template, which is nothing more than a text with some named placeholders.
  • Some content to be filled in for the placeholders of the template.
  • A program that determines the content that is to be filled in for the placeholders.

For flexibility we allow anything that can be written out as text to be content. Now we consider that a template which has all its placeholder filled in with some content can be written out as text, i.e. such a filled in template itself makes pretty good content.

So the essential idea is that template processing is a back and for between templates and a program that determines content to be filled in.

tmpl_n_content.png

Templates with text content and filled templates as content.

The Template 3 in the figure above has its two placeholders filled in – aka bound – and therefore can be used as content for Template 1. Note that also Template 2, that has no placeholders, can be used as content because all of its placeholders, actually none, are bound.

Dynamic Content

Though the illustration above is a rather static example it is important to mention, that content can be much more than static, predefined pieces. If the program that we write has some sort of conditional content or some sort of repetitive content, we have the flexibility we need to create complex output. Fortunately modern programming paradigms give us the tools to easily express such dynamic content. In any object oriented language it should be quite easy to have abstract content that overrides a write method. In Java it could be similar to this:

public interface Content {
    void write( PrintWriter wr );
}

...
    public void processTemplate( Template t, PrintWriter wr )
    {
        final String[] strls = new String { "foo", "bar", "baz" };
        t.bind( "place", new Content() {
            private List<Template> tls = new ArrayList<>();
            {
                int count = 1;
                for ( String str : strls ) {
                    Template lineTmpl = loadATemplate( "line-template" );
                    lineTmpl.bind( "num", count++ );
                    lineTmpl.bind( "str", str );
                    tls.add( lineTmpl );
                }               
            }
            @Override void write( PrintWriter wr )
            {
                for ( Template t : tls )
                    t.write( wr );
            }
        } );
        t.write( wr );
    }
...

However with functional programming style this would be much more elegant, e.g. with C++ 11 we could allow any std::function<void (std::ostream&)> as content and write:

void process_template( Template& t, std::ostream& os )
{
  using namespace std;
  vector<string> strls{ "foo", "bar", "baz" };
  vector<Template> tls;
  int count = 1;
  for ( const string& str : strls ) {
    Template lineTmpl = load_a_template( "line-template" );
    lineTmpl.bind( "num", count++ );
    lineTmpl.bind( "str", str );
    tls.push_back( lineTmpl );
  }
  t.bind( "place",
          [&tls]( ostream& os ) { for ( const Template& t : tls ) os << t; } );
  os << t;
}

Templates and Binding

Though the examples in the previous section showed how to nest bound templates as content into templates, the examples also give a hint where the design should be "tuned". We reuse the so called line-template over and over to create output for each element in the strls list of strings. It is very likely, that loading of templates needs quite some processing. At least there has to be some parsing of a template "text" to find the placeholders but locating and loading from disk or somewhere else is very likely too.

This is why we split templates into two parts:

  1. The Template that is immutably kept around to be used to generate some output.
  2. The bound template, Bount in the following, that references the Template it binds content to and the content that is bound to the placeholders.

tmpl_n_bount.png

A bound template is also content.

With this simple design at the core of Toxic the general ideas should be easy to grasp. Note that there is no special, proprietary template language to learn! You can don anything with templates what your programming language allows you to do when overriding Content::write() and you can do it with your programming language in your IDE.

However that seems to put the burden of overriding Content::write() on you – which indeed is the case. But as one might see in the current Java implementation this could easily be solved by writing useful libraries of special Content.

Author: Marcus Perlick

Date: May 25, 2014

HTML generated with emacs org-mode & Toxic by [qb]