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 :

<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 :

<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 :

  <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 :

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):

# 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:

<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:

[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

.