Plain Text Templates

Let's start with an example:

<% queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o").eachWithIndex{ it, i -> %>
This is row #${i}. It contains the following objects:
<% it.eachWithIndex{ jt, j -> %>
  Object #${j}: Class = ${jt.objectType().value()}, name = ${jt.name()}
<% if (jt.objectType().value() == "{SomeNamespace}ROUser") { %>
      It is responsible for ${jt.ResponsibleFor.name()}.
<% } } } %>

And here's some sample output:

This is row #0. It contains the following objects:

  Object #0: Class = {SomeNamespace}ROUser, name = SomeUser

      It is responsible for SomeOrg.

  Object #1: Class = {SomeNamespace}ROOrg, name = SomeOrg

The query engine

Have a look at the following snippet from the template:

<% queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o") %>

This is a so-called scriptlet. A scriptlet contains embedded Groovy source code. Basically, the template engine iterates over the template contents. Simple text is just copied, but scriptlets are executed when they are encountered by the template engine.

The example runs a query, which performs a JOIN over multiple object types. Keep in mind, that such queries are returning a list of rows: Each of the rows contains an array of registry objects. This is why we use the method queryEngine.queryArray: Otherwise, we'd use queryEngine.query.

Loops

As you might have noticed, we have intentionally shortened the scriptlet in the previous section. Actually, the scriptlet was

<% queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o").eachWithIndex{ it, i -> %>
  ...
<% } %>

Recall, that the query returns a list of rows. The Groovy instruction eachWithIndex iterates over these rows. For any iteration, it assigns the row to the variable it, and the row number to the variable i. We are using the latter variable in the following snippet:

This is row #${i}. It contains the following objects:

If you look into the output, then you should notice that the query returned a single row with number 0.

But there's another loop: The rows returned by the queries are in fact arrays of registry object. We iterate over these registry objects in the inner loop.

<% it.eachWithIndex{ jt, j -> %>
  ...
<% } %>

For any registry object in the row, a variable jt, and a variable j are created, and the following snippet is entered:

  Object #${j}: Class = ${jt.objectType().value()}, name = ${jt.name()}

The snippets output would look like this:

  Object #0: Class = {SomeNamespace}ROUser, name = SomeUser

In other words, the initial sample output shows you, that row number 0 contained two registry objects.

Interpolation

We have already noticed simple examples of interpolation: The snippets $i, and $j have been used to emit the row, and column number, respectively. But interpolation can be quite complex, as the next snippet shows us: $jt.objectType().value() would invoke the method objectType() on the registry object jt, then the method value() on the object type.

Conditional evaluation

It is more than likely, that you'd sooner or later like to enable or disable certain parts of the template. Conditional evaluation allows you to do just that:

<% if (jt.objectType().value() == "{SomeNamespace}ROUser") { %>
      It is responsible for ${jt.ResponsibleFor.name()}.
<% } %>

As you can see in the output, the text snippet is enabled for Object #0, because it is an instance of SomeNamespaceROUser, but not for Object #1, which is an instance of SomeNamespaceROUser.

Predefined variables

The template engine provides a number of predefined variables:

Variable nameDescription
queryEngineThe query engine, an instance of QueryEngine.
metaModelAccessorThe meta model accessor, an instance of ROMetaModelAccessor.
modelAccessorThe model accessor, an instance of ROModelAccessor.
registryFacadeThe registry facade, an instance of RegistryFacade.
registryMetaModelThe registry meta model, an instance of ROMetaModel.