Skip to content

cobigen core_configuration

travis edited this page Sep 20, 2019 · 65 revisions

Configuration

CobiGen will be configured using a configuration folder containing a context configuration, multiple template folders with a templates configuration per template folder, and a number of templates in each template folder. Find some examples here. Thus, a simple folder structure might look like this:

CobiGen_Templates
 |- templateFolder1
    |- templates.xml
 |- templateFolder2
    |- templates.xml
 |- context.xml

Context Configuration

The context configuration (context.xml) always has the following root structure:

Context Configuration
<?xml version="1.0" encoding="UTF-8"?>
<contextConfiguration xmlns="http://capgemini.com" 
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                      version="1.0">
    <triggers>
        ...
    </triggers>
</contextConfiguration>

The context configuration has a version attribute, which should match the XSD version the context configuration is an instance of. It should not state the version of the currently released version of CobiGen. This attribute should be maintained by the context configuration developers. If configured correctly, it will provide a better feedback for the user and thus higher user experience. Currently there is only the version v1.0. For further version there will be a changelog later on.

Trigger Node

As children of the <triggers> node you can define different triggers. By defining a <trigger> you declare a mapping between special inputs and a templateFolder, which contains all templates, which are worth to be generated with the given input.

trigger configuration
<trigger id="..." type="..." templateFolder="..." inputCharset="UTF-8" >
    ...
</trigger>
  • The attribute id should be unique within an context configuration. It is necessary for efficient internal processing.

  • The attribute type declares a specific trigger interpreter, which might be provided by additional plug-ins. A trigger interpreter has to provide an input reader, which reads specific inputs and creates a template object model out of it to be processed by the FreeMarker template engine later on. Have a look at the plug-in’s documentation of your interest and see, which trigger types and thus inputs are currently supported.

  • The attribute templateFolder declares the relative path to the template folder, which will be used if the trigger gets activated.

  • The attribute inputCharset (optional) determines the charset to be used for reading any input file.

Matcher Node

A trigger will be activated if its matchers hold the following formula:

!(NOT || …​ || NOT) && AND && …​ && AND && (OR || …​ || OR)

Whereas NOT/AND/OR describes the accumulationType of a matcher (see below) and e.g. NOT means 'a matcher with accumulationType NOT matches a given input'. Thus additionally to an input reader, a trigger interpreter has to define at least one set of matchers, which are satisfyable, to be fully functional. A <matcher> node declares a specific characteristics a valid input should have.

Matcher Configuration
<matcher type="..." value="..." accumulationType="...">
    ...
</matcher>
  • The attribute type declares a specific type of matcher, which has to be provided by the surrounding trigger interpreter. Have a look at the plug-in’s documentation, which also provides the used trigger type for more information about valid matcher and their functionalities.

  • The attribute value might contain any information necessary for processing the matcher’s functionality. Have a look at the relevant plug-in’s documentation for more detail.

  • The attribute accumulationType (optional) specifies how the matcher will influence the trigger activation. Valid values are:

    • OR (default): if any matcher of accumulation type OR matches, the trigger will be activated as long as there are no further matchers with different accumulation types

    • AND: if any matcher with AND accumulation type does not match, the trigger will not be activated

    • NOT: if any matcher with NOT accumulation type matches, the trigger will not be activated

VariableAssignment Node

Finally, a <matcher> node can have multiple <variableAssignment> nodes as children. Variable assignments allow to parametrize the generation by additional values, which will be added to the object model for template processing. The variables declared using variable assignments, will be made accessible in the templates.xml as well in the object model for template processing via the namespace variables.*.

Complete Configuration Pattern
<?xml version="1.0" encoding="UTF-8"?>
<contextConfiguration xmlns="http://capgemini.com" 
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                      version="1.0">
    <triggers>
        <trigger id="..." type="..." templateFolder="...">
            <matcher type="..." value="...">
                <variableAssignment type="..." key="..." value="..." />
            </matcher>
        </trigger>
    </triggers>
</contextConfiguration>
  • The attribute type declares the type of variable assignment to be processed by the trigger interpreter providing plug-in. This attribute enables variable assignments with different dynamic value resolutions.

  • The attribute key declares the namespace under which the resolved value will be accessible later on.

  • The attribute value might declare a constant value to be assigned or any hint for value resolution done by the trigger interpreter providing plug-in. For instance, if type is regex, then on value you will assign the matched group number by the regex (1, 2, 3…​)

ContainerMatcher Node

The <containerMatcher> node is an additional matcher for matching containers of multiple input objects. Such a container might be a package, which encloses multiple types or---more generic---a model, which encloses multiple elements. A container matcher can be declared side by side with other matchers:

ContainerMatcher Declaration
<?xml version="1.0" encoding="UTF-8"?>
<contextConfiguration xmlns="http://capgemini.com" 
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                      version="1.0">
    <triggers>
        <trigger id="..." type="..." templateFolder="..." >
            <containerMatcher type="..." value="..." retrieveObjectsRecursively="..." />
            <matcher type="..." value="...">
                <variableAssignment type="..." variable="..." value="..." />
            </matcher>
        </trigger>
    </triggers>
</contextConfiguration>
  • The attribute type declares a specific type of matcher, which has to be provided by the surrounding trigger interpreter. Have a look at the plug-in’s documentation, which also provides the used trigger type for more information about valid matcher and their functionalities.

  • The attribute value might contain any information necessary for processing the matcher’s functionality. Have a look at the relevant plug-in’s documentation for more detail.

  • The attribute retrieveObjectsRecursively (optional boolean) states, whether the children of the input should be retrieved recursively to find matching inputs for generation.

The semantics of a container matchers are the following:

  • A <containerMatcher> does not declare any <variableAssignment> nodes

  • A <containerMatcher> matches an input if and only if one of its enclosed elements satisfies a set of <matcher> nodes of the same <trigger>

  • Inputs, which match a <containerMatcher> will cause a generation for each enclosed element

Templates Configuration

The template configuration (templates.xml) specifies, which templates exist and under which circumstances it will be generated. There are two possible configuration styles:

  1. Configure the template meta-data for each template file by template nodes

  2. (since cobigen-core-v1.2.0): Configure templateScan nodes to automatically retrieve a default configuration for all files within a configured folder and possibly modify the automatically configured templates using templateExtension nodes

To get an intuition of the idea, the following will intially describe the first (more extensive) configuration style. Such an configuration root structure looks as follows:

Extensive Templates Configuration
<?xml version="1.0" encoding="UTF-8"?>
<templatesConfiguration xmlns="http://capgemini.com" 
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                        version="1.0" templateEngine="FreeMarker">
    <templates>
            ...
    </templates>
    <increments>
            ...
    </increments>
</templatesConfiguration>
The root node <templatesConfiguration> specifies two attributes. The attribute version provides further usability support and will be handled analogous to the version attribute of the context configuration. The optional attribute templateEngine specifies the template engine to be used for processing the templates (since cobigen-core-4.0.0). By default it is set to FreeMarker. The node <templatesConfiguration> allows two different grouping nodes as children. First, there is the <templates> node, which groups all declarations of templates. Second, there is the <increments> node, which groups all declarations about increments.

Template Node

The <templates> node groups multiple <template> declarations, which enables further generation. Each template file should be registered at least once as a template to be considered.

Example Template Configuration
<templates>
    <template name="..." destinationPath="..." templateFile="..." mergeStrategy="..." targetCharset="..." />
    ...
</templates>

A template declaration consist of multiple information:

  • The attribute name specifies an unique ID within the templates configuration, which will later be reused in the increment definitions.

  • The attribute destinationPath specifies the destination path the template will be generated to. It is possible to use all variables defined by variable assignments within the path declaration using the FreeMarker syntax ${variables.*}. While resolving the variable expressions, each dot within the value will be automatically replaced by a slash. This behavior is accounted for by the transformations of Java packages to paths as CobiGen has first been developed in the context of the Java world. Furthermore, the destination path variable resolution provides the following additional built-in operators analogue to the FreeMarker syntax:

    • ?cap_first analogue to FreeMarker

    • ?uncap_first analogue to FreeMarker

    • ?lower_case analogue to FreeMarker

    • ?upper_case analogue to FreeMarker

    • ?replace(regex, replacement) - Replaces all occurrences of the regular expression regex in the variable’s value with the given replacement string. (since cobigen-core v1.1.0)

    • ?removeSuffix(suffix) - Removes the given suffix in the variable’s value iff the variable’s value ends with the given suffix. Otherwise nothing will happen. (since cobigen-core v1.1.0)

    • ?removePrefix(prefix) - Analogue to ?removeSuffix but removes the prefix of the variable’s value. (since cobigen-core v1.1.0)

  • The attribute templateFile describes the relative path dependent on the template folder specified in the trigger to the template file to be generated.

  • The attribute mergeStrategy (optional) can be optionally specified and declares the type of merge mechanism to be used, when the destinationPath points to an already existing file. CobiGen by itself just comes with a mergeStrategy override, which enforces file regeneration in total. Additional available merge strategies have to be obtained from the different plug-in’s documentations (see here for java, XML, properties, and text). Default: not set (means not mergable)

  • The attribute targetCharset (optional) can be optionally specified and declares the encoding with which the contents will be written into the destination file. This also includes reading an existing file at the destination path for merging its contents with the newly generated ones. Default: UTF-8

(Since version 4.1.0) It is possible to reference external template (templates defined on another trigger), thanks to using <incrementRef …​> that are explained here.

TemplateScan Node

(since cobigen-core-v1.2.0)

The second configuration style for template meta-data is driven by initially scanning all available templates and automatically configure them with a default set of meta-data. A scanning configuration might look like this:

Example of Template-scan configuration
<?xml version="1.0" encoding="UTF-8"?>
<templatesConfiguration xmlns="http://capgemini.com" 
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                        version="1.2">
    <templateScans>
        <templateScan templatePath="templates" templateNamePrefix="prefix_" destinationPath="src/main/java"/>
    </templateScans>
</templatesConfiguration>
You can specify multiple <templateScan …​> nodes for different templatePaths and different templateNamePrefixes.
  • The name can be specified to later on reference the templates found by a template-scan within an increment. (since cobigen-core-v2.1.)

  • The templatePath specifys the relative path from the templates.xml to the root folder from which the template scan should be performed.

  • The templateNamePrefix (optional) defines a common id prefix, which will be added to all found and automatically configured templates.

  • The destinationPath defines the root folder all found templates should be generated to, whereas the root folder will be a prefix for all found and automatically configured templates.

A templateScan will result in the following default configuration of templates. For each file found, new template will be created virtually with the following default values:

  • id: file name without .ftl extension prefixed by templateNamePrefix from template-scan

  • destinationPath: relative file path of the file found with the prefix defined by destinationPath from template-scan. Furthermore,

    • it is possible to use the syntax for accessing and modifying variables as described for the attribute destinationPath of the template node, besides the only difference, that due to file system restrictions you have to replace all ?-signs (for built-ins) with #-signs.

    • the files to be scanned, should provide their final file-ending by the following file naming convention: <filename>.<fileending>.ftl Thus the file-ending .ftl will be removed after generation.

  • templateFile: relative path to the file found

  • mergeStrategy: (optional) not set means not mergable

  • targetCharset: (optional) defaults to UTF-8

(Since version 4.1.0) It is possible to reference external templateScan (templateScans defined on another trigger), thanks to using <incrementRef …​> that are explained here.

TemplateExtension Node

(since cobigen-core-v1.2.0)

Additionally to the templateScan declaration it is easily possible to rewrite specific attributes for any scanned and automatically configured template.

Example Configuration of a TemplateExtension
<templates>
    <templateExtension ref="prefix_FooClass.java" mergeStrategy="javamerge" />
</templates>

<templateScans>
    <templateScan templatePath="foo" templateNamePrefix="prefix_" destinationPath="src/main/java/foo"/>
</templateScans>

Lets assume, that the above example declares a template-scan for the folder foo, which contains a file FooClass.java.ftl in any folder depth. Thus the template scan will automatically create a virtual template declaration with id=prefix_FooClass.java and further default configuration.

Using the templateExtension declaration above will reference the scanned template by the attribute ref and overrides the mergeStrategy of the automatically configured template by the value javamerge. Thus we are able to minimize the needed templates configuration.

(Since version 4.1.0) It is possible to reference external templateExtension (templateExtensions defined on another trigger), thanks to using <incrementRef …​> that are explained here.

Increment Node

The <increments> node groups multiple <increment> nodes, which can be seen as a collection of templates to be generated. An increment will be defined by a unique id and a human readable description.

<increments>
    <increment id="..." description="...">
        <incrementRef ref="..." />
        <templateRef ref="..." />
        <templateScanRef ref="..." />
    </increment>
</increments>

An increment might contain multiple increments and/or templates, which will be referenced using <incrementRef …​>, <templateRef …​>, resp. <templateScanRef …​> nodes. These nodes only declare the attribute ref, which will reference an increment, a template, or a template-scan by its id or name.

(Since version 4.1.0) An special case of <incrementRef …​> is the external incrementsRef. By default, <incrementRef …​> are used to reference increments defined in the same templates.xml file. So for example, we could have:

<increments>
    <increment id="incA" description="...">
        <incrementRef ref="incB" />
    </increment>
    <increment id="incB" description="...">
        <templateRef .... />
        <templateScan .... />
    </increment>
</increments>

However, if we want to reference an increment that it is not defined inside our templates.xml (an increment defined for another trigger), then we can use external incrementRef as shown below:

<increment name="..." description="...">
    <incrementRef ref="trigger_id::increment_id"/>
</increment>

The ref string is split using as delimiter ::. The first part of the string, is the trigger_id to reference. That trigger contains an increment_id. Currently, this functionality only works when both templates use the same kind of input file.

Java Template Logic

since cobigen-core-3.0.0 which is included in the Eclipse and Maven Plugin since version 2.0.0 In addition, it is possible to implement more complex template logic by custom Java code. To enable this feature, you can simply import the the CobiGen_Templates by clicking on Adapt Templates, turn it into a simple maven project (if it is not already) and implement any Java logic in the common maven layout (e.g. in the source folder src/main/java). Each Java class will be instantiated by CobiGen for each generation process. Thus, you can even store any state within a Java class instance during generation. However, there is currently no guarantee according to the template processing order.

As a consequence, you have to implement your Java classes with a public default (non-parameter) constructor to be used by any template. Methods of the implemented Java classes can be called within templates by the simple standard FreeMarker expression for calling Bean methods: SimpleType.methodName(param1). Until now, CobiGen will shadow multiple types with the same simple name indeterministically. So please prevent yourself from that situation.

Finally, if you would like to do some reflection within your Java code accessing any type of the template project or any type referenced by the input, you should load classes by making use of the classloader of the util classes. CobiGen will take care of the correct classloader building including the classpath of the input source as well as of the classpath of the template project. If you use any other classloader or build it by your own, there will be no guarantee, that generation succeeds.

Template Properties

since cobigen-core-4.0.0 Using a configuration with template scan, you can make use of properties in templates specified in property files named cobigen.properties next to the templates. The property files are specified as Java property files. Property files can be nested in subfolders. Properties will be resolved including property shading. Properties definied nearest to the template to be generated will take precedence. In addition, a cobigen.properties file can be specified in the target folder root (in eclipse plugin, this is equal to the source project root). These properties take precedence over template properties specified in the template folder.

Note
It is not allowed to override context variables in cobigen.properties specifications as we have not found any interesting use case. This is most probably an error of the template designer, CobiGen will raise an error in this case.

Multi module support or template target path redirects

since cobigen-core-4.0.0 One special property you can specify in the template properties is the property relocate. It will cause the current folder and its subfolders to be relocated at destination path resolution time. Take the following example:

folder
  - sub1
    Tempalte.java.ftl
    cobigen.properties

Let the cobigen.properties file contain the line relocate=../sub2/${cwd}. Given that, the relative destination path of Template.java.ftl will be resolved to folder/sub2/Template.java. Compare template scan configuration for more information about basic path resolution. The relocate property specifies a relative path from the location of the cobigen.properties. The ${cwd} placeholder will contain the remaining relative path from the cobigen.properties location to the template file. In this basic example it just contains Template.java.ftl, but it may even be any relative path including subfolders of sub1 and its templates. Given the relocate feature, you can even step out of the root path, which in general is the project/maven module the input is located in. This enables template designers to even adress, e.g., maven modules located next to the module the input is coming from.

Basic Template Model

In addition to what is served by the different model builders of the different plug-ins, CobiGen provides a minimal model based on context variables as well as CobiGen properties. The following model is independent of the input format and will be served as a template model all the time:

Plugin Mechanism

Since cobigen-core 4.1.0, we changed the plug-in discovery mechanism. So far it was necessary to register new plugins programmatically, which introduces the need to let every tool integration, i.e. for eclipse or maven, be dependent on every plug-in, which should be released. This made release cycles take long time as all plug-ins have to be integrated into a final release of maven or eclipse integration.

Now, plug-ins are automatically disovered by the Java Service Loader mechanism from the classpath. This also effects the setup of eclipse and maven integrations to allow modular releases of CobiGen in future. We are now able to provide faster rollouts of bugfixes in any of the plug-ins as they can be released completely independently.

Clone this wiki locally