Tag: FMPP

Code generator with ant FMPP and FreeMarker

CodeDevEnglish

A simple code generator example with FMPP and FreeMarker with the help of ant and antelope for automation.

Content :
– Why should we do code generators ?
– How it works
– Prepare ant tasks
– Let’s try with a simple file
– Now let’s do something bigger

Why should we do code generators
Some people are…pretty anxious when I advocate the use of a code generator. Most of the time they think spending time on a code generator isn’t productive enough for their short term objectives… These kind of person spend their lives running to catch a train that goes to fast for their capacity. Actually, code generators are a perfect answer for short term project, but not the first one (and again this isn’t obvious).

Code generators are part of your company’s (or personal) normalisation, industrialisation, and process simplification.
– Developers can focus more on business than technical implementation,
– Maintenance is easier : all code base is similar
– If your company turnover is important, process are simpler to acquire

So actually you can code faster, with a better quality, the ROI is always (if code generator is correctly done) positive.

How it works
Creating a code generator project is really fast, just :
1- use a real project you want to generate and copy it somewhere,
2- identify the dynamic stuff inside this project, like :
– classnames,
– packages,
– folders,
– …
3- replace dynamic patterns with a property tag
4- generate it once and do the adjustments if needed

In order to have an idea, a code generator creating around fifty files, that creates a Flex module with BlazeDS Java endpoints takes about 4 hours of work and tuning before beiing live.

Prepare ant tasks
Download Fmpp and AntelopeTasks jars and put them inside your ANT_HOME/lib folder.
Then inside your build.xml add those 2 lines after your project definition :

1
2
<taskdef name="antelope" classname="ise.antelope.tasks.StringUtilTask" />
<taskdef name="fmpp" classname="fmpp.tools.AntTask" />

Now to use fmpp just do something like this inside a target :

1
2
3
4
5
6
<fmpp sourceRoot="${basedir}/src/MODULE/entity_and_code"
      outputroot="${module_base_dir}/${entity_and_code}"
      alwaysCreateDirectories="true"
      logfile="${basedir}/logs/${entity_and_code}.log" >
  <data>antProperties()</data>
</fmpp>

Antelope in this project will be used mostly for its lowercase/upperCase/replace commands. Example :

1
2
3
4
5
6
7
<property name="entity_and_code" value="${entity_and_project}_${module_code}" />
<antelope string="${entity_and_code}" property="entity_and_code">
  <lowercase />
</antelope>
<antelope string="${entity_and_code}" property="ENTITY_AND_CODE">
  <uppercase />
</antelope>

Let’s try with a simple file

You can get the files here : QQ_CG01.tar

The src folder contains this hierarchy : fr/quidquid/sample/flex/modules/MODULE_CODE
This folder contains the ModuleConstants.as file.

Inside the ModuleConstants.as file you’ll find freemarker tags :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package ${module_base_package}.flex.${module_code}
{
    public class  ModuleConstants{
 
        // ***********************************************
        // ******** EVENTS FOR ${module_code?upper_case}_${module_name}
 
        public static const EVENT_${module_code?upper_case}_TESTBUTTON_SUBMIT:String = "EVENT_${module_code?upper_case}_TESTBUTTON_SUBMIT";
 
        // ####_DO_NEVER_(RE)MOVE_THIS_LINE_NOR_CHANGE_IT_#### EVENTS
 
        // ***********************************************
        // ******** NOTIF FOR ${module_code?upper_case}_${module_name}
 
        public static const NOTIF_${module_code?upper_case}_I18N_GET_OK:String = "NOTIF_${module_code?upper_case}_I18N_GET_OK";
 
        // ####_DO_NEVER_(RE)MOVE_THIS_LINE_NOR_CHANGE_IT_#### NOTIF
 
    }
}

Our goal is to replace these tags and after generation rename the MODULE_CODE folder with the right name.

First step to see how it works, in the root folder open the PROJECT.properties, it contains our dynamic stuffs (quite simple on this example):

1
2
3
4
5
6
7
8
9
# Output folder of the code generator
output_dir = OUT
 
# Base package, will be suffixed with the module_code upper case
module_base_package = fr.quidquid.sample.flex.modules
# Functionnal name
module_name = Quidquid Test
# Module unique name in the whole application
module_code = QQT01

Then let’s look at the build.xml file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<project name="SimpleCodeGenerator" default="generate" basedir=".">
 
  <!-- Initialize antelope and fmpp -->
  <taskdef name="antelope" classname="ise.antelope.tasks.StringUtilTask" />
  <taskdef name="fmpp" classname="fmpp.tools.AntTask" />
 
  <target name="generate">
 
    <!-- Get properties from property file -->
    <property file="${basedir}/PROJECT.properties" />
 
    <!-- I need module_code to be lower case -->
    <antelope string="${module_code}" property="module_code">
      <lowercase />
    </antelope>
     
    <!-- I need module_base_package to be lower case -->
    <antelope string="${module_base_package}" property="module_base_package">
      <lowercase />
    </antelope>
    <!-- Get the path from the package ( just replaces . with / )-->
    <antelope string="${module_base_package}" property="module_base_path">
      <replace regex="\." replacement="/" />
    </antelope>
 
    <!-- MODULE GENERATION -->
    <fmpp sourceRoot="${basedir}/src/"
          outputroot="${output_dir}/"
          alwaysCreateDirectories="true"
          logfile="${basedir}/${module_code}.log" >
      <data>antProperties()</data>
    </fmpp>
 
    <!-- Rename the module folder -->
    <move todir="${output_dir}/${module_base_path}/${module_code}">
      <fileset dir="${output_dir}/${module_base_path}/MODULE_CODE" />
    </move>
 
  </target>
 
</project>

You can now open a command line ant do:

1
[julien@mars QQ_CG01]# ant

Output should be something like:

Now you should have an OUT folder containing your fr/quidquid/sample/flex/modules/qqt01/ModuleConstants.as with all the freemarker tags replaced… Easy no ?

Some freeMarker expressions you can use:
${module_code?upper_case}
${module_code?lower_case}
${module_code?cap_first}

To change the name of a filename:
<@pp.dropOutputFile />
<@pp.changeOutputFile name=module_name?cap_first + "Mediator.as" />

Well just go through the manual: http://freemarker.sourceforge.net/docs/dgui_template_exp.html

.