4.6.2. AutoFormat Example

As an example of implementing an Auto-Format transformation, this section describes the source code of the Auto-Format class org.docma.plugin.examples.ApplyTemplate, which is included in the Docmenta installation package. See Section 1.9.2, “Dynamic Templates” for more information on how to use this class. Following illustration depicts the template concept that is implemented by the class:

Figure 4.6.8. ApplyTemplate example

The illustration explained in words: The notebox style has the org.docma.plugin.examples.ApplyTemplate class with argument "notebox_template" assigned. That means, input-elements which have the notebox style assigned are transformed by this class. The ApplyTemplate class replaces the input-element by the content of a template. The template is identified by the alias which is passed as argument (here: "notebox_template"). Furthermore, the transformation replaces the substring "$content" within the template by the inner content of the input-element and the substring "$title" by the title-attribute of the input-element.
Following the source code of the org.docma.plugin.examples.ApplyTemplate class, that implements this template concept:
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 
42 
43 
44 
45 
46 
47 
package myexample;
import org.docma.plugin.*;
import java.io.*;
 
public class ApplyTemplate implements AutoFormat
{
private ExportContext exportCtx;
public void initialize(ExportContext ctx)
{
exportCtx = ctx;
}
public void finished()
{
exportCtx = null;
}
public void transform(TransformationContext ctx) throws Exception
{
String alias = ctx.getArgument(0);
String template =
exportCtx.getContentStringByAlias(alias, true);
if (template == null) {
throw new Exception("Could not find template with alias "
+ alias);
}
String title = ctx.getTagAttributes().get("title");
if (title == null) title = "";
Writer out = ctx.getWriter();
out.write(template.replace("$content", ctx.getInnerString())
.replace("$title", title));
}
public String getShortInfo(String languageCode)
{
return PluginUtil.getResourceString(this.getClass(),
languageCode, "shortInfo");
}
public String getLongInfo(String languageCode)
{
return PluginUtil.getResourceString(this.getClass(),
languageCode, "longInfo");
}
}

Listing 4.6.1. ApplyTemplate.java

An Auto-Format transformation is a Java class that implements the interface org.docma.plugin.AutoFormat. The interface consists of following five methods: initialize, finished, transform, getShortInfo and getLongInfo.
The method initialize is intended for initialization of a new instance of the Auto-Format class, i.e. it is always called by the export process before the method transform is called for the first time. The method gets an instance of the class org.docma.plugin.ExportContext as argument, which provides access to the context of the running export. This includes
  • reading the content of a node within the product tree
  • getting the user interface language
  • getting the export language and format
  • getting a GenText property value
  • decoding/encoding character entities
  • writing to the export log
In this example the method just assigns the argument to the field exportCtx. This way the method transform, which is called for each element to be transformed, also has access to the export context.
The method finished is called by the export process as soon as the complete export of the publication is finished. Therefore this method can be used to release any resources that have been allocated by the Auto-Format class. In this example it just sets the field exportCtx to null (this is not required, though it allows the garbage collector to release memory, which is allocated by the export context, as early as possible).
The method transform actually executes the transformation of an element. This method is called by the export process each time an element within the publication has to be transformed by this Auto-Format class. That means, only one instance of the Auto-Format class is used for one export process. The method gets an instance of the class org.docma.plugin.TransformationContext as argument, which gives access to the element to be transformed and provides a writer object to write the transformation result.
When an Auto-Format class is assigned to a style, the user can set Auto-Format arguments. With Auto-Format arguments the behavior of an Auto-Format class can be parameterized. The ApplyTemplate class expects one argument, which is the alias name of the content-node to be used as template. The Auto-Format arguments can be retrieved from the transformation context. Therefore, the first action within the method transform is to get the first Auto-Format argument from the transformation context:
String alias = ctx.getArgument(0);
The returned alias name is then used to retrieve the template-content:
String template = exportCtx.getContentStringByAlias(alias, true);
If no content-node with the given alias name is found, an exception is thrown. Note that throwing an exception will cause an error message in the export log. However the export continues without transforming the element. The next action is to retrieve the value of the input-element's title attribute:
String title = ctx.getTagAttributes().get("title");
If no title attribute is defined in the input-element, then the empty string is used as title:
if (title == null) title = "";
Then the substring "$content" within the template is replaced by the inner content of the input-element:
template.replace("$content", ctx.getInnerString())
and the substring "$title" is replaced by the title value:
.replace("$title", title)
Finally, the resulting string is returned as transformation result:
Writer out = ctx.getWriter();
out.write(...);
The method getShortInfo is intended to return a human-readable text describing the purpose of this Auto-Format transformation in one sentence. The method getLongInfo is intended to return a complete usage reference, including a description of all supported Auto-Format arguments. The returned text of both methods is displayed to the user of the Auto-Format class. For better readability the text returned by method getLongInfo can include XHTML tags, which allows basic formatting of the text. The text which is returned by both methods should be in the language given by the argument languageCode. At least the language code "en" has to be supported (i.e. the descriptions have to be available at least in English).
For long descriptions and to allow the translation of the descriptions without having to touch the source code of the classes, the text returned by the methods getShortInfo and getLongInfo should be stored in external resource files. You can use the static method getResourceString of the utility class org.docma.plugin.PluginUtil to load a language dependent property from an external resource file, as shown in this example. The path of the resource file is derived from the provided class and language code by replacing all dots within the full-qualified class name by a dash ("/"), appending the language code separated by an underscore and attaching the file extension ".xml". Therefore, in our example the path to the resource file for the English language (language code "en") is org/docma/plugin/example/ApplyTemplate_en.xml. In other words, a resource file with name ApplyTemplate_en.xml has to be located in the same folder where the corresponding class file is located (usually packaged in a jar archive).
The format of the resource file is the XML properties format as used by the Java class java.util.Properties (see the Java Standard Edition API documentation for more information). Following an example of the resource file ApplyTemplate_en.xml:
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="shortInfo">Format input using a template</entry>
<entry key="longInfo"><![CDATA[
<big><b>Arguments:</b></big>
<ul>
<li><b><tt><i>ALIAS</i></tt></b>:
<br />The alias name of the template node.</li>
</ul>
<p><big><b>Description:</b></big></p>
<p>
The content-node given by alias name <tt><i>ALIAS</i></tt>
is used as a template. It is assumed that the template content
contains the substrings "<tt>$title</tt>" and "<tt>$content</tt>".
</p>
]]>
</entry>
</properties>

Listing 4.6.2. ApplyTemplate_en.xml

Note that a CDATA section is used for the value of the longInfo property, because the property value contains XHTML tags, which would otherwise interfere with the XML properties format. By using a CDATA section, the < and > characters do not have to be encoded as character entities (&lt; and &gt;).
To use the Auto-Format transformation, just place the compiled ApplyTemplate class together with the resource file ApplyTemplate_en.xml into the class path of the Docmenta application.
Improving the performance
As mentioned above, the transform method is called for each occurence of an element to be transformed. Therefore, the performance can be improved by caching the template content. Following listing gives the improved source code of the ApplyTemplate class (the changed lines are highlighted):
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 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
package myexample;
import org.docma.plugin.*;
import java.util.*;
import java.io.*;
public class ApplyTemplate implements AutoFormat
{
private ExportContext exportCtx;
private Map<String, String> templateMap;
public void initialize(ExportContext ctx)
{
exportCtx = ctx;
templateMap = new HashMap<String, String>();
}
public void finished()
{
exportCtx = null;
templateMap = null;
}
public void transform(TransformationContext ctx) throws Exception
{
String alias = ctx.getArgument(0);
String template = templateMap.get(alias);
if (template == null) {
template = exportCtx.getContentStringByAlias(alias, true);
if (template == null) {
throw new Exception("Could not find template with alias "
+ alias);
}
templateMap.put(alias, template);
}
String title = ctx.getTagAttributes().get("title");
if (title == null) title = "";
Writer out = ctx.getWriter();
out.write(template.replace("$content", ctx.getInnerString())
.replace("$title", title));
}
public String getShortInfo(String languageCode)
{
return PluginUtil.getResourceString(this.getClass(),
languageCode, "shortInfo");
}
public String getLongInfo(String languageCode)
{
return PluginUtil.getResourceString(this.getClass(),
languageCode, "longInfo");
}
}

Listing 4.6.3. ApplyTemplate.java (improved)

Note that different styles can have different Auto-Format arguments. That means, it is not sufficient to cache a single template. In the implementation above a java.util.HashMap object stores the cached templates. The alias of the template is used as key which is mapped to the template content.