User guide

RTFTempate use case

RTFTemplate use case is design your RTF model with MS Word and then merge it with JAVA object context. With RTFTemplate you can :

Here steps for creating your RTF model :

Create your Context

Before design your source RTF model, I adwice you to prepare your context. That's to say, create all JAVA object (POJO and Collection of POJO) putted in your context for merging it with your RTF model source.

RTFTemplate project contains abstract class AbstractUseCase, which is able to use RTFtemplate quickly to test your RTF model, to generate RTF file target and XML fields available :

  public abstract class AbstractUseCase {
  
    /**
     * Run RTFTemplate for merging rtfSource with the context 
     * putted with the method putContext which be must implement.
     * After execution of this method, files 
     * rtfSource + ".velocity.rtf" (RTF source with macro velocity) and 
     * rtfSource + ".out.rtf" (RTF final with values of the context)
     * will be generate.
     * @param rtfSource RTF source model.
     * @throws Exception
     */
    protected final void run(String rtfSource) throws Exception {
      ....
    }

    /**
     * This method must be implement by class
     * wich manage your RTF model. 
     * Put the context of your model
     * (eg : template.put("date", new Date()); ) 
     * @param template RTFTemplate
     */
    protected abstract void putContext(RTFTemplate template);
    
    /**
     * Return String XML Mergefields used in your context
     * and Bookmarks (for start and end loop)  
     * @return
     */
    public String getXMLFields() {
      ....
    }
    
    /**
     * Save XML fields available into file.
     * If force parameter is false, the file is 
     * updated with new context (by keeping just 
     * description) otherwise the file is 
     * crushed with new context.
     * @param filename
     * @throws Exception
     */
    protected void saveXmlFields(String filename, boolean force) throws Exception {
      ....
    }
    
    /**
     * set true if RTF with velocity macro file must be generated
     * and false otherwise.
     * @param saveRTFVelocity
     */
    public void saveRTFVelocity(boolean saveRTFVelocity) {
      ....
    }
  }

You must implement class which extends AbstractUseCase and implement methods :

  • putContext : in this method, put the context of your model. For the collection it's very important to put at least one JAVA object, in order to RTFTemplate generate correctly the velocity macro #foreach (for manage iteration).
  • putDefaultFormat : in this method, put the format used to display value of JAVA object. For instance, you can format all getter of your JAVA object context type of java.util.Date with specific pattern, like this :
      engine.setDefaultFormat(Date.class, DateFormat.getDateInstance());

Once that you implement the class, you can call methods :

  • run : to test and generate the RTF target.
  • getXMLFields : to get XML fields available for your RTF model. This XML String can be used after when you will design your RTF model with MS Word.
  • saveXmlFields : to save XML fields available for your RTF model into XML file.
  • saveRTFVelocity : set to true if you want generate RTF with velocity macro and false otherwise. By default, AbstractUseCase doesn' generate RTF file with velocity macro.

Here an example of class which test your RTF model :

  public class RTFProjectTest extends AbstractUseCase {
        
    protected void putContext(RTFTemplate template) {
      /**
       * Context of simply POJO
       */      
      template.put("date", new Date());
      template.put("project", new Project("Jakarta Velocity"));
      
      /**
       * Context of list of POJO
       */
      List developers = new ArrayList();
      Developer developer = new Developer("Will Glass-Husain", "wglass@apache.org");
      developer.addRole("Java Developer");
      developer.addRole("Release Manager");
      ....
      template.put("developers", developers );
    }
        
    /**
     * Use case of RTFTemplate with the RTF source model <b>project_model.rtf</b>.
     * It generate two files : 
     * <ul>
     *  <li><b>project_model.velocity.rtf</b> RTF with velocity macro.</li>
     * </ul>
     * <ul>
     *  <li><b>project_model.out.rtf</b> RTF final with value of the context.</li>
     * </ul>
     * @param args
     */
    public static void main( String[] args ) throws Exception {
        RTFProjectTest usecase = new RTFProjectTest();
        usecase.run("usecases/project/project_model.rtf");
        usecase.saveRTFVelocity(true); // Save RTF file with velocity macro
        // Display the XML fields 
        System.out.println(usecase.getXMLFields()); 
        // Save XML fields into project_model.fields.xml file with update description
        usecase.saveXmlFields("usecases/project/project_model.fields.xml" ,false);
    }
}  

Pattern configuration for Bookmark start and loop

For manage iteration you must use Bookmark for start and end loop in your RTF model. By default, patterns used by RTFTemplate are :

  • START_LOOP_{i} for start the ith iteration of your model.
  • END_LOOP_{i} for end the ith iteration of your model.

    But it's possible to config this pattern if you don' want use this pattern. You could use french pattern like this :

  • DEBUT_BOUCLE_{i} for start the ith iteration of your model.
  • FIN_BOUCLE_{i} for end the ith iteration of your model.

For that you must create XML file my-transformer-config like this :

  <?xml version="1.0" encoding="ISO-8859-1"?>
  <transformer-config>
          <bookmark-start-loop>
                  <pattern>DEBUT_BOUCLE_{i}</pattern>
          </bookmark-start-loop>
          <bookmark-end-loop>
                  <pattern>FIN_BOUCLE_{i}</pattern>
          </bookmark-end-loop>
  </transformer-config>
  

To use this XML file, you must configure RTFTemplate engine with RTFTemplate method setTransformerConfigFile :

  ....
  RTFTemplateEngine engine = new RTFTemplateEngine( ve );
  ....
  template.setTransformerConfigFile("my-transformer-config.xml");

If you use AbstractUseCase, you must call method setTransformerConfigFile before run method :

    RTFProjectTest usecase = new RTFProjectTest();
    usecase.setTransformerConfigFile("usecases/project/my-transformer-config.xml");
    usecase.run("usecases/project/project_model.rtf");

Design your RTF model

For designing your RTF model, you must use :

  • MERGEFIELD for manage object value.
  • HYPERLINK is like MERGEFIELD. Use it when you want generate link (like email).
  • BOOKMARK for manage iteration.

    To create your mergefields/hyperlinks (Menu Insert/Fields...) and bookmarks (Menu Insert/Bookmark) you can use MS Word. You can too use Macro Word which has been developed to display fields avalaible for your model.

    This macro use XML file which contains Mergefields avalaible for your model and pattern used for Bookmark start/end loop. This file must be ended by extension .fields.xml in order to macro detect that this file is XML fields available.

Integrate RTFTemplate engine in your project.

It's very important to understand RTFTemplate process and difference between RTFTemplate and RTFVelocityTemplate, when you decide to integrate RTFTemplate in your project. In your real Project, I adwice not use AbstractUseCase. It's better to initialize RTFTemplate as you want. AbstractUsCase use velocity context for create #foreach. You can have troubles (with #foreach) when your real context doesn't contains all JAVA object into the list context, see RTFTemplate & Velocity context section for more explanation.

Here 2 steps while RTFTemplate process :

  • Step 1 : generate RTF template with velocity macro by using RTF model created by MS word.
  • Step 2 : merge JAVA object with RTF template (with velocity macro).

Step 1 must be perfectly understood :

  • You must understand, the 2 means to generate RTF model with velocity macro :
    • RTFTemplate & Velocity context : pay attention to with this solution for #foreach generation (all data must be contained into velocity context).
    • RTFTemplate & XML fields available : I adwice to use this solution for generate RTF model with velocity macro. To obtain this XML fields file, launch your AbstractUseCase (which contains all possible data in velocity context).
  • You must choose your generation strategy
    • RTF Velocity Stored strategy, when you want optimize RTFtemplate process. For this, you could generate RTF with velocity macro one time (by using RTFTemplate) and store it (into file or database). Then you can generate RTF target by using RTF with velocity macro stored (by using RTFVelocityTemplate).
    • RTF Velocity Reader strategy, when you want use RTFtemplate without store RTF model with velocity macro (this last is a stream) (by using just RTFTemplate).

How manage object value ?

Object value are designed by MERGEFIELD or HYPERLINK. With this RTF fields, you can apply it RTF style (Bold, Color, Police...) with MS Word. But when you are applying style, pay attention to select the whole field, otherwise you will are troubles on RTF target.
Name of your MERGEFIELD must use velocity syntax. For display value of Name of Project JAVA object :

  public class Project {

      private String name;
      
      public Project(String name) {
              this.name = name;
      }

      public String getName() {
              return name;
      }

      public void setName(String name) {
              this.name = name;
      }
  }

putted into context with key project :

template.put("project", new Project("Jakarta Velocity"));

the name of MERGEFIELD must be $project.Name.

How manage iteration ?

When you design your RTF model with MS word, you want often display list of items. Sometimes you want display list of items into RTF table (several RTF row), sometimes you want manage iteration on list of items like display list of items seperated by , character. This section explains how manage iteration by using MS word and give several use cases.

At first, when you want manage iteration with MS word, you must use particulary MERGEFIELD. Indead, iteration must be done on MERGEFIELD type of list. MERGEFIELD are defined by name. The name of MERGEFIELD is associated with an object JAVA putted into velocity context at the time of merging template and context. This name is the key of the object JAVA putted into velocity context. If object JAVA is type of list (like java.util.Collection, java.util.List...) MERGEFIELD are type of list. When you design your RTF model, you can use RTFTemplate macro word to know all MERGEFIELD availables for the model and know if MERGEFIELD are type of list or not.

Once you insert MERGEFIELD type of list in your RTF model, you must specify the start and the end of iteration. Generally, iteration is managed by BOOKMARK. A BOOKMARK is single in your model RTF. You must create BOOKMARK :

  • START_LOOP_{i} for start the ith iteration of your model.
  • END_LOOP_{i} for end the ith iteration of your model.

A MERGEFIELD type of list must be included inside of this two BOOKMARK. The inconveniant with BOOKMARK, is that it's difficult to detect it in your RTF model, but the favour is that you can insert BOOKMARK anywhere in your model.

With MS Word, by default bookmarks are not visible. To show bookmarks, you must go to Tools menu/Options... In the tab Display, you must check show bookmarks option.

However, when you want iterate on MERGEFIELD type of list, and display each items into RTF row, it's impossible to place correctly BOOKMARK. Where is the start of RTF row, where is the end? You can do it when you have one RTF row, but there are problems when you want generate RTF Table with RTF row Header and RTF row which must be iterate.

To resolve this problems RTFTemplate iterate on RTF row, when there is a a cell of row which contains a MERGEFIELD type of list. But sometimes, you want display iterate on MERGEFIELD list which is included into RTF row, but you don't want iterate just on the row, but iterate for example on title (before RTF row) with RTF row. How do it? Here rules to manage iteration :

  • case 1 : Iterate on list of items when MERGEFIELD (type list) is included into two Bookmarks (START_LOOP_ and END_LOOP_) and NOT included into RTF row. For instance you want generate list of items separated by , character, like this :
    item1, item2,
    

    To obtain this case you must insert in your RTF model :

     * START_LOOP_1 Bookmark
     * MERGEFIELD (list of item) , 
     * END_LOOP_1 Bookmark
  • case 2 : Iterate on list of items when MERGEFIELD (type list) is included into RTF row and this last is NOT included into two Bookmarks (START_LOOP_ and END_LOOP_). For instance you want generate RTF table (iteration on RTF row) :
    -------------------
    |item1|     |     |
    -------------------
    |item2|     |     |
    -------------------

    To obtain this case you must insert in your RTF model :

     * RTF Row 
       * MERGEFIELD (list of item) inserted into cell of RTF row. 
       
  • case 3 : Iterate on list of items when MERGEFIELD (type list) is included into two Bookmarks (START_LOOP_ and END_LOOP_) and Bookmarks are included into RTF row. For instance you want generate one RTF row which has cell which contains list of items separated by , character, like this :
    --------------------------
    |item1, item2|     |     |
    --------------------------

    To obtain this case you must insert in your RTF model :

     * RTF Row 
       * START_LOOP_1 Bookmark inserted into cell of RTF row. 
       * MERGEFIELD (list of item) inserted into cell of RTF row. 
       * END_LOOP_1 Bookmark inserted into cell of RTF row.
       
  • case 4 : Iterate on list of items when MERGEFIELD (type list) is included RTF row and this last is included into two Bookmarks (START_LOOP_ and END_LOOP_). For instance when you manage group of Title/RTF row and iterate on list of items :
    My Title
    -------------------
    |item1|     |     |
    -------------------
    
    My Title
    -------------------
    |item2|     |     |
    -------------------
    

    To obtain this case you must insert in your RTF model :

     * START_LOOP_1 Bookmark
     * My Title
     * RTF Row 
       * MERGEFIELD (list of item) inserted into cell of RTF row. 
     * END_LOOP_1 Bookmark
                 
  • case 5 : Iterate on list of items when MERGEFIELD (type list) is included RTF row and before this row there are another RTF row (Header of RTF table) :
    ----------------------------
    |Header 1|Header 2|Header 3|
    ----------------------------
    |item1   |        |        |
    ----------------------------
    

    This case is particulary, because it depends on RTF row Header. Indead, if Header have no style you must use Bookmark start/end for manage loop, like this :

     * RTF Row Header
     * START_LOOP_1 Bookmark (after end of RTF row header)
     * RTF Row 
       * MERGEFIELD (list of item) inserted into cell of RTF row. 
     * END_LOOP_1 Bookmark (after end of RTF row with MERGEFIELD)
    

    if Header have style you must NOT use Bookmark start/end for manage loop, like this :

     * RTF Row Header
     * RTF Row 
       * MERGEFIELD (list of item) inserted into cell of RTF row. 
    

    You must do like this, because sometimes MS Word generate RTF row (first case) that RTFTemplate is not able to detect (start and end RTFRow is impossible to detect). That's why you must use Bookmark for managing iteration. Is it a BUG??? If anybody is an expert on RTF code, I would like an explanation for correct this problem with RTFTemplate. If you give style in RTF header row, there are no problems. So don't use Bookmark for managing iteration (otherwise, your RTF row with MERGEFIELD will have style of Header).

How manage page break ?

With RTF template you can iterate on list of item and add Page break after each items. RTF template is able to not insert Page break on last item in order to avoid add blank RTF page after last item. For this, you must design your RTF model, like this :

 * START_LOOP_1 Bookmark (at start your RTF document)
 * MERGEFIELD (list of item) 
 * other RTF content...
 * RTF Page (break)
 * END_LOOP_1 Bookmark

It's too possible to group items of list and generate after each group a page break. For manage this, you can call method setGroupByPerPageBreak of RTFTemplate instance, like this :

        template.setGroupByPerPageBreak(4); 

This exemple will generate 4 items, and after it will generate a page break.

How manage image ?

With RTFTemplate you can add Image in your RTF model. For this, you must insert MERGEFIELD. Getter of Java Object must return InputStream, stream of your Image. RTFTemplate support PNG, JPG, EMF and BPM format.

How manage user properties ?

With word you can create user properties. To do that, you can access to user properties with menu File/Propeties. In Customization Tab you can create user property (Name, value and type). With RTFTemplate user property or list of user property is managing like MERGEFIELD.

  • If you want that RTFTemplate replace Value/Name user property by your value comming from context, you must create user property with syntax velocity (eg : $myUserPropertyValue). See section How manage object value ?
  • If you want manage list of user property, you must create user property with name $myList.UserPropertValue and value $myList.UserPropertName. In your context you must put java list with contains object with getter getUserPropertValue and getUserPropertName. See section How manage iteration ?

XML fields available

Name of MERGEFIELD/HYPERLINK and BOOKMARK pattern (for start/end loop) used in your RTF model source is very important. It depends on your JAVA object context of your model. MS Word Macro used, when you are designing RTF model use XML fields available file. This file describes fields (MERGEFIELD/HYPERLINK) that you can use in your RTF model and BOOKMARK pattern.

Here an example of XML fields :

<?xml version="1.0" encoding="ISO-8859-1"?>
<fields>
  <description><![CDATA[Fields (Mergefield and Bookmark) availables for the model RTF Project Velocity Jakarta.]]></description>
  <bookmark>
          <type>START_LOOP</type>
          <name>START_LOOP_{i}</name>
          <description><![CDATA[Start of loop.]]></description>
  </bookmark>
  <bookmark>
          <type>END_LOOP</type>
          <name>END_LOOP_{i}</name>
          <description><![CDATA[End of loop.]]></description>
  </bookmark>
  <mergefield>
          <list>true</list>
          <name>$dependencies.ArtifactID</name>
          <description><![CDATA[]]></description>
  </mergefield>
  ...
  <mergefield>
          <list>false</list>
          <name>$project.Name</name>
          <description><![CDATA[]]></description>
  </mergefield>
...
</fields>

This XML file contains XML elements :

  • description (after root fields), which describes your RTF model.
  • bookmark which describes pattern for start/end loop :
    • type : START_LOOP for describing start pattern loop and END_LOOP for end pattern loop.
    • name : pattern for loop. {i} must be used in the pattern.
    • description : description of bookmart loop type.
  • mergefield which describes pattern for start/end loop :
    • list : true id MERGEFIELD/HYPERLINK is list (eg : comming from java.util.List) and false otherwise (comming from object JAVA POJO).
    • name : name of MERGEFIELD/HYPERLINK which use velocity syntax.
    • description : description of mergefield.