Class FreeMarkerExtension
- All Implemented Interfaces:
ReportFactoryExtension
An extension to use the Apache FreeMarker template library as a pre-processor to generate the HTML/XML parsed by BFO Publisher.
This extension is invoked by including a <?freemarker href="template.ftl"?> processing
instruction at the start of the document - the href attribute refers
to the template, so the document being parsed is an XML representation of the data.
The example from the FreeMarker documentation
could be created as
<?freemarker href="path/to/template.ftl"?>
<data>
<user>Big Joe</user>
<latestProduct>
<url>products/greenmouse.html</user>
<name>green mouse</user>
</latestProduct>
</data>
The processing instruction doesn't have to be added to the XML; it can be added via the API:
Report report = reportFactory.createReport();
ProcessingInstruction pi = new ProcessingInstruction().setType("freemarker").put("href", "path/to/template.ftl"");
report.getProcessingInstructions().add(pi);
report.load(new File("data.xml"));
report.parse();
PDF pdf = output.getPDF();
pdf.render(new FileOutputStream("out.pdf"));
XML isn't the only way to represent data; the technique of manually
adding a processing instruction can also be applied to data stored as JSON, CBOR or in a
FreeMarker TemplateModel. For JSON or CBOR it is parsed the same way as XML;
any stream, file or URL with a media-type of application/json or application/cbor will be
passed through FreeMarker, so long as the freemarker
processing-instruction has been added via the API. So to convert JSON, the code sample directly
above would be modified only to change the file to JSON, eg report.load(new File("data.json"));
To load from a TemplateModel, just pass it in to the Report.load() method:
Report report = reportFactory.createReport();
ProcessingInstruction pi = new ProcessingInstruction("freemarker", "href=\"path/to/template.ftl\"");
report.getProcessingInstructions().add(pi);
Map<String,String> data = loadDataModel(); // Your method
FreeMarkerExtension ext = reportFactory.getReportFactoryExtension(FreeMarkerExtension.class);
Configuration cfg = ext.getConfiguration();
report.load(cfg.getObjectWrapper().wrap(data));
report.parse();
PDF pdf = output.getPDF();
pdf.render(new FileOutputStream("out.pdf"));
Template format and relative paths
By default the output of any Template is assumed to be HTML
(even when the file containing the data is XML, as shown in the first example above).
If the template outputs XML instead,
set the type attribute on the processing instruction to text/xml. In XML:
<?freemarker type="text/xml" href="path/to/template.ftl?>
or in Java, either of these
new ProcessingInstruction("freemarker", "type=\"text/html\" href=\"path/to/template.ftl\"");
new ProcessingInstruction().setType("freemarker").put("type", "text/html").put("href", "path/to/template.ftl");
Relative paths in the template will be resolved relative to the template file, not relative to the input.
Configuration
Any properties in the map returned from Report.getEnvironment() and
ReportFactory.getEnvironment() that begin with freemarker. will be
passed to the Configuration (for ReportFactory.getEnvironment()) or
Environment (for Report.getEnvironment()), minus the freemarker.
prefix.
Security
BFO Publisher has no control over Freemarker Template processing, and as Freemarker currently has
no "runaway" checks, a careless or malicious template could easily create an OutOfMemoryError.
To mitigate this, FreeMarker Templates must always be loaded from a trusted URL -
see URLConnectionFactory.isTrusted(org.faceless.publisher.type.URL2). By default
this means the resolved Template URL must have a scheme of classpath, file
or jar, or if loading from a MemoryURLConnectionFactory the
AbstractBlob.isTrusted() method must return true.
- Since:
- 1.3
- See Also:
-
MustacheExtension
-
Constructor Summary
ConstructorsConstructorDescriptionCreate a new FreeMarkerExtensionFreeMarkerExtension(Configuration conf) Create a new FreeMarkerExtension -
Method Summary
Modifier and TypeMethodDescriptionvoidconfigure(Json json) Configure the FreeMarker extension.ConfigurationReturn the FreeMarker Configuration.booleanReturn the value set bysetThreads(boolean)booleanIf the template represented by this class requires it to be loaded from a trusted sourcebooleanAttempt to load the specified object into the specified Report.voidNotify this object it has beem added to a Report.voidregister(ReportFactory factory) Notify this object it has beem added to a ReportFactory.voidsetConfiguration(Configuration conf) Set the FreeMarker Configuration.voidsetThreads(boolean threads) Set whether to use two threads when converting the Template.voidunregister(ReportFactory factory) Notify this object it has been removed from a ReportFactory.Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface org.faceless.publisher.ext.ReportFactoryExtension
unregister
-
Constructor Details
-
FreeMarkerExtension
public FreeMarkerExtension()Create a new FreeMarkerExtension -
FreeMarkerExtension
public FreeMarkerExtension(Configuration conf) Create a new FreeMarkerExtension- Parameters:
conf- the FreeMarker Configuration to pass tosetConfiguration(Configuration)
-
-
Method Details
-
setConfiguration
public void setConfiguration(Configuration conf) Set the FreeMarker Configuration. If this is not specified by the time the first FreeMarker document is converted, a default Configuration will be used. This method can only be called once.- Parameters:
conf- the FreeMarker Configuration to pass tosetConfiguration(Configuration)
-
getConfiguration
public Configuration getConfiguration()Return the FreeMarker Configuration. If one has not been set previously, this will callsetConfiguration()with a default configuration. -
configure
public void configure(Json json) Configure the FreeMarker extension.
Currently only the the boolean parameter
threadscan be set to callsetThreads(boolean)- Specified by:
configurein interfaceReportFactoryExtension- Parameters:
json- the json configuration
-
load
Attempt to load the specified object into the specified Report. Ifobjectis aTemplateModel. this method will use theTemplatespecified by thefreemarkerProcessingInstructionto load the input. Otherwise it will return false.- Specified by:
loadin interfaceReportFactoryExtension- Parameters:
object- the object to load, which could be aTemplateModelreport- the report- Returns:
- true if this object can be loaded by this extension, false otherwise.
- Throws:
IOException
-
unregister
Description copied from interface:ReportFactoryExtensionNotify this object it has been removed from a ReportFactory. Will be called when this object is removed from the list returned byReportFactory.getReportFactoryExtensions(). The default implementation is a no-op.- Specified by:
unregisterin interfaceReportFactoryExtension
-
register
Description copied from interface:ReportFactoryExtensionNotify this object it has beem added to a ReportFactory. Will be called when this object is added to the list returned byReportFactory.getReportFactoryExtensions(). The default implementation is a no-op.- Specified by:
registerin interfaceReportFactoryExtension
-
register
Description copied from interface:ReportFactoryExtensionNotify this object it has beem added to a Report. Will be called when this object is added to the list returned byReportFactory.getReportFactoryExtensions(). The default implementation is a no-op.- Specified by:
registerin interfaceReportFactoryExtension
-
isTrustRequired
public boolean isTrustRequired()If the template represented by this class requires it to be loaded from a trusted source -
setThreads
public void setThreads(boolean threads) Set whether to use two threads when converting the Template.By default only a single thread is used; the output from the template+object is written to a String, and after it completes that String is fed into the XML parser to create the Report.
Setting
Depending on the implementation of the template library, using two threads should prevent the entire XML document from being stored in memory, which will be beneficial when small or mid-size templates are combined with large models to create extremely large output.threadstotruewill convert the template+object in a new Thread, with the output from that Thread piped into the main Thread to convert to a Report.- Parameters:
threads- whether to use two Threads when applying the Template
-
isThreads
public boolean isThreads()Return the value set bysetThreads(boolean)
-