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
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.
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.
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.
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.
The template engine provides a number of predefined variables:
Variable name | Description |
---|---|
queryEngine | The query engine, an instance of QueryEngine. |
metaModelAccessor | The meta model accessor, an instance of ROMetaModelAccessor. |
modelAccessor | The model accessor, an instance of ROModelAccessor. |
registryFacade | The registry facade, an instance of RegistryFacade. |
registryMetaModel | The registry meta model, an instance of ROMetaModel. |