Creating Templates

Bootstrap was designed with the goal of making it as easy as possible to develop code templates. Bootstrap supports multiple template languages. Velocity has been selected as the default template language for its ease of use compared to alternative languages such as XML (e.g. XDoclet – verbose) and JSP-like (a confusing mix of text and XML). The template language should: be simple, produce human-readable code, be extensible, and not be verbose.

An example template is as follows: package ${owner}.${appName}.dao; import java.util.List; import net.sf.bootstrap.framework.dao.DAO; import ${owner}.${appName}.model.${cls.name}; public interface ${cls.name}DAO extends DAO { /** * Get a list of all recorded #spacedPlural($cls.name). * * @return the list of all #spacedPlural($cls.name). */ public List findAll#plural($cls.name)(); ...

Templates are organised into modules that are deployed as either a directory or JAR file into the ‘modules’ sub-directory of the ‘bootstrap-working’ directory.

Each module requires an XML configuration file named ‘codegen.xml’. The schema of this file is as follows: <?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bootstrap.sourceforge.net" xmlns="http://bootstrap.sourceforge.net" elementFormDefault="qualified"> <xs:element name="module"> <xs:complexType> <xs:sequence> <xs:element name="package" type="packagetype" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required"/> </xs:complexType> </xs:element> <xs:complexType name="packagetype"> <xs:sequence> <xs:element name="template" type="templatetype" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="level" type="xs:string" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="project"/> <xs:enumeration value="class"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="type" type="xs:string" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="java"/> <xs:enumeration value="resources"/> <xs:enumeration value="webapp"/> <xs:enumeration value="build"/> <xs:enumeration value="cs"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="location" type="xs:string" use="required"/> </xs:complexType> <xs:complexType name="templatetype"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="name" type="xs:string" use="required"/> <xs:attribute name="templateEngine" type="xs:string"/> <xs:attribute name="unless" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:schema>

For example: <?xml version="1.0"?> <module name="dao"> <package level="class" type="java" location="dao"> <template name="${cls.name}DAO.java">DAO.vm</template> </package> </module>

The module name is the name of the sub-project to which the source code is placed.

A package represents a collection of templates of the same level, type, and location.

A template is code template which generates a source file.

The package level may be ‘project’ or ‘class.’ Project level templates are generated once for the project and receive the collection of all meta-classes. Class level templates are generated for each class.

The package type indicates the type of source file to be generated, which also determines the location. The package location indicates the sub-directory path under the general location determined by type.

The body of the template element is the name of the template file. The ‘name’ attribute of template is the name of the source file to be generated. The name may include a variable (in Velocity syntax) of any meta-data property available at the package level. For example: ${cls.name} will substitute in the name of the particular class being processed.

The ‘unless’ attribute of template is an expression that is used to determine whether to skip generation of that template. The expression may include variables from the meta-data available at the package level and using syntax from the expression language. Bootstrap can support multiple expression languages (specified in the Spring configuration file). Velocity is used by default. The expressions must evaluate to a Boolean result. (The Velocity content must use the Boolean condition in an if-else statement to produce a ‘true’ or ‘false’ return string. The Boolean condition itself when evaluated by Velocity does not produce a string result that can be converted to a Java Boolean.)