« prev index next »

12. Writing Celerio Templates

Introduction

Celerio code generation templates are written in Velocity.

Celerio can either execute templates packaged in a jar file or templates that are present in a regular folder.

Jaxio provides some ready-to-use generation templates. These templates are packaged in template packs.

A template pack is a simple jar. To be executed by Celerio this jar file must be explicitly added as a Celerio’s dependency when running Celerio.

New template packs can be written either by Jaxio’s consultants or Celerio’s end users.

Learn by example

The simplest way to get started with Celerio templates is to modify existing templates.

Jaxio provides the following Open Source template packs:

Templates folder

Before starting, update your Celerio configuration in order to specify a template folder location.

In src/main/config/celerio-maven-plugin/celerio-templates-packs.xml declare your Celerio template source folder using the template pack element. For example:

<packs>
	<!-- ... other packs skipped... -->
	<pack name="pack-custom" path="src/main/my-pack" enable="true" />
</packs>

Celerio expects to find in the declared src/main/my-pack folder 2 subfolders:

src
   |- main
          |- my-pack
                  |- META-INF
                  |- celerio	                                

Content of META-INF and celerio sub-folders is described below.

Create a templates pack

A template pack is simply a set of Celerio templates packaged in a jar file. The project (assuming you are using Maven) must have the following structure:

pom.xml
src
   |- main
          |- resources
                      |- META-INF
                      |          |- celerio-pack.xml
                      |
                      |- celerio
                                |- bootstrap
                                |           |- pom.boot.vm.xml
                                |           |- anytemplate.boot.vm.xml
                                |
                                |- pack-the-name-of-the-pack
                                                          |- **/yourtemplate.e.vm.java

The celerio-pack.xml file contains some meta information that Celerio engine and the Celerio bootstrap-maven-plugin use. Here is a celerio-pack.xml file example:

<?xml version="1.0" encoding="UTF-8"?>
<celerioPack xmlns="http://www.jaxio.com/schema/celerio">
    <packName value="pack-the-name-of-the-pack"/>
    <packDescription value="My sample pack"/>
    <packDescription2 value="Generates entities, meta model, repositories to access entities etc. Used by front-end packs."/>
    <packCommand value="mvn -Pdb,metadata,gen test"/>
    <packCommandHelp value=""/>
    <projectLink value="https://github.com/jaxio/my-pack"/>
</celerioPack>

It is important that the packName starts with the prefix pack-.

Template name conventions

There are several kinds of templates.

Bootstrap template

A bootstrap template is interpreted only when Celerio is run in bootstrap mode. The bootstrap mode is active when you use the Celerio’s bootstrap-maven-plugin.

Its name must have this form: TemplateName.boot.vm.ext or TemplateName.ext.boot.vm where:

Example: pom.boot.vm.xml or pom.xml.boot.vm.

Per entity template

A per entity template is interpreted for each entity. Its name must have this form: TemplateName.e.vm.ext or TemplateName.ext.e.vm where:

Example: Controller.e.vm.java or Controller.java.e.vm

Per project template

A per project template is interpreted one time per projet. Its name must have this form: TemplateName.p.vm.ext or TemplateName.ext.p.vm where:

Example: web.p.vm.xml or web.xml.p.vm

Per enum template

A per enum template is interpreted for each enum. Its name must have this form: TemplateName.enum.vm.ext or TemplateName.ext.enum.vm

Example: EnumController.enum.vm.java or EnumController.java.enum.vm

Per composite primary key template

A per composite primary key template is interpreted for each composite primary key. Its name must have this form: TemplateName.cpk.vm.ext or TemplateName.ext.cpk.vm where:

Example: CompositePkBridge.cpk.vm.java or CompositePkBridge.java.cpk.vm

Static files

Static files are not interpreted, they are just copied as is by Celerio.

Exemple: afolder/img.gif would be copied to yourProjectRootFolder/afolder/img.gif

Template context

The template context is the Velocity execution context. It exposes your project metamodel and various facilities.

Here is the list of object variables present in the template context:

output

Full javadoc: output - TemplateExcecution

The output has several roles:

output controls where to write the result of the template evaluation

At the beginning of your template, use output to specify where to write the generated file. For example:

$output.java($Root,"MyClass")

Writes the result of the template evaluation to src/main/generated-java/your-root-package/MyClass.java

** Note **: Check the full list of GeneratedPackage, that you can pass as the first argument of $output.java

$output.java($WebSecurity, "LoginForm")##

Writes the result of the template evaluation to src/main/java/your-root-package/web/security/LoginForm.java

** Note **: the class name is available using $output.currentClass

output manages Java imports

One of the challenge of writing a Java template is to manage the Java imports. You have to make sure that you do not import twice the same class or that you do not import useless classes.

$output.require or $output.requireStatic methods help you in this task.

$output.require("org.apache.shiro.SecurityUtils")##

Make sure “import org.apache.shiro.SecurityUtils;” is present in the generated file.

Note that you can use $output.require conditionally, anywhere in your template code, for example:

#if(something)
$output.requireStatic("com.google.common.collect.Lists.newArrayList")
$output.require("java.util.List")
#end

In case ‘something’ evals to true, the 2 import statements will be properly inserted in your generated java file, not in the middle of a Java method of course.

output provides helper for annotation and Java imports

$output.dynamicAnnotation("com.company.project.MyAnnotation")

returns @MyAnnotation and ensure import com.company.project.MyAnnotation; statement is properly generated.

project

The project is the metamodel root. The project contains all the entities.

Full javadoc: project - Project

entity

The entity references the current entity when working with per entity or composite pk templates

Full javadoc: entity - Entity

** Root and primary key **

** Lists **

The entity gives you access to various kind of lists. Lists are often encapsulated in a SimpleListHolder or a CurrentAndFlatListHolder.

The list contains mainly the following types:

** namers **

The entity provides getters to predefined Namer. see section below.

enum

The enum references the current enum when working with per enum template

Full javadoc: enum - EnumType

** example: **

public class $output.currentClass extends GenericEnumController<${enum.model.type}> { ...

Entity Namers

Full javadoc: Namer

An entity namer allows you to construct easily some var/method/class name that are derived from the current entity name. The entity object, has several built-in namers but other namers can be created using Celerio configuration.

One of the most used namer is the model namer. Assuming that the current entity full name is com.example.domain.Bank here are the various value returned when invoking the namer’s methods:

Another commonly used namer is the repository namer, here are more returned value example:

By default Celerio has some built-in namers. Theses can be used from your entity templates:

Create an entity namer

Let’s assume that:

Here is the content of the entityAcl.e.vm.java template that you may create:

$output.java($entity.acl)##

public class $output.currentClass {
    // var: $entity.acl.var
    // type: $entity.acl.type
    // etc...
}

The ‘acl’ entity’s property implements Celerio’s Namer Interface. The Namer interface exposes simple getter methods to access var name, getter name, etc…

Before running Celerio with the above template, you must first create the ‘acl’ Namer. To do so, open the celerio-template-packs.xml file and add the following celerioTemplateContext element:

<packs>
	<celerioTemplateContext>
		<entityContextProperties>
			<entityContextProperty property="acl" subPackage="security" suffix="Acl"/>
		</entityContextProperties>
	</celerioTemplateContext>

	<!-- ... other packs skipped... -->
	<pack name="pack-custom" path="src/main/celerio" enable="true" />
</packs>

Celerio Service Provider Interface

Celerio exposes the following SPIs:

You can create some extension by following ServiceLoader convention. Your extension must be packaged in a jar file containing your classes and the expected service files.

src
   |- main
          |- resources
                      |- META-INF
                                 |- services
                                            |
                                            - com.jaxio.celerio.spi.ProjectSpi
                                            - com.jaxio.celerio.spi.EntitySpi
                                            - com.jaxio.celerio.spi.AttributeSpi
                                            - com.jaxio.celerio.spi.RelationSpi

You extension implementation must be listed in one of the file above.

Assuming you have created an entity extension whose full type is com.jaxio.celerio.spi.example.ExampleEntity, the content of the com.jaxio.celerio.spi.EntitySpi file must be:

com.jaxio.celerio.spi.example.ExampleEntity

Here is our dummy ExampleEntity extension source code:

package com.jaxio.celerio.spi.example;

import com.jaxio.celerio.model.Entity;
import com.jaxio.celerio.spi.EntitySpi;

public class ExampleEntity implements EntitySpi {

    private Entity entity;

    @Override
    public void init(Entity entity) {
        this.entity = entity;
    }

    @Override
    public String velocityVar() {
        return "example";
    }

    public String getHello() {
        return "Hello from ExampleEntity: this entity has " + entity.getCurrentAttributes().size() + " attributes";
    }
}

To activate it and be able to use it through $entity.example and invoke $entity.example.hello from your templates, add the extension’s jar as a dependency when running celerio-maven-plugin, for example:

		<profile>
			<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
			<!-- Generate the code using Celerio -->
			<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
			<id>gen</id>
			<build>
				<defaultGoal>generate-sources</defaultGoal>
				<plugins>
					<plugin>
						<groupId>com.jaxio.celerio</groupId>
						<artifactId>celerio-maven-plugin</artifactId>
						<version>${celerio-maven-plugin.version}</version>
						<executions>
							<execution>
								<id>Generates files using the extracted database schema.</id>
								<goals>
									<goal>generate</goal>
								</goals>
							</execution>
						</executions>
						<dependencies>
							<dependency>
								<groupId>com.jaxio.celerio.packs</groupId>
								<artifactId>pack-backend-jpa</artifactId>
								<version>1.0.0</version>
							</dependency>
							<dependency>
								<groupId>com.yourcompany.celerio</groupId>
								<artifactId>my-celerio-extension</artifactId>
								<version>1.0.0</version>
							</dependency>
						</dependencies>
					</plugin>
				</plugins>
			</build>

© 2005-2015 Jaxio | @jaxiosoft | Legal