Daniel Dekany
2015-08-08 15:29:39 UTC
Any insight with the below new feature? It's implemented and committed
BTW (2.3-gae), but can be seen as a proof-of-the-concept...
Something FM was missing is a way of specifying different
Configuration settings for different templates. You have a common
Configuration, and all templates that you get from that via
getTemplate(...) has the same configuration settings, inherited from
the Configuration (apart from locale that you can specify to
getTemplate(...)). While Template always had setter methods to
override the settings, with Configurable.getTemplate(...) you have no
chance to call them. (You could call them after getTemplate, but that
would not thread safe, etc.)
Planned features, such as true auto-escaping will need such
functionality. Like you might want *.ftlh to be automatically HTML
escaped, but not for *.ftl. (That's something I ran into recently,
though I have used Velocity there...)
So I came up with TemplateConfigurer, which is an object on which you
can set settings (from freemarker.core.Configurable), which it can set
in Template like myTemplateCfger.configure(template). A
TemplateConfigurer can also hold settings that influence parsing (like
tag_syntax, etc., from freemarker.core.ParserConfiguration, which is
also new in 2.3.24), and can even specify the charset to used for
loading the template (if you ever had a mix of UTF-8 and
ISO-8859-<x>/CP<x> templates...).
Then, I have added a new Configuration setting, called
"templateConfigurers". It's type is
freemarker.cache.TemplateConfigurerFactory, which is basically a
collection of TemplateConfigurer-s, plus rules that tell that
depending on the name of the template (the "source name" that the
TemplateLoader uses), when to apply which. Using the Properties-based
configuration syntax of FreeMarker for brevity (the Java config would
be the same, but with bunch of `new`-s and setXxx-s), it's something
like this:
MergingTemplateConfigurerFactory(
FirstMatchTemplateConfigurerFactory(
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.de.*'),
TemplateConfigurer(timeZone=TimeZone('GMT+01'), locale=Locale('de', 'DE'))),
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.fr.*'),
TemplateConfigurer(timeZone=TimeZone('GMT'), locale=Locale('fr', 'FR'))),
allowNoMatch=true
),
FirstMatchTemplateConfigurerFactory(
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.ftlh'),
TemplateConfigurer(outputFormat='HTML')),
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.ftlx'),
TemplateConfigurer(outputFormat='XML')),
noMatchErrorDetails='Unrecognized template file extension'
),
ConditionalTemplateConfigurerFactory(
PathGlobMatcher('stat/**')
TemplateConfigurer(timeZone=TimeZone('UTC'))
)
)
The "outputFormat" setting above is hypothetical, we don't yet have
it.
So if you set this as the "templateConfigurers", and you get a
template called "foo.de.ftlh", then that Template will have locale
de_DE, time zone GMT+01 and outoutFormat (again, hypothetical) "HTML".
For "stats/foo.de.ftlh" the time zone will be UTC instead (because
when merging, the last setting value assignment wins).
So that's it. Opinions, ideas?
BTW (2.3-gae), but can be seen as a proof-of-the-concept...
Something FM was missing is a way of specifying different
Configuration settings for different templates. You have a common
Configuration, and all templates that you get from that via
getTemplate(...) has the same configuration settings, inherited from
the Configuration (apart from locale that you can specify to
getTemplate(...)). While Template always had setter methods to
override the settings, with Configurable.getTemplate(...) you have no
chance to call them. (You could call them after getTemplate, but that
would not thread safe, etc.)
Planned features, such as true auto-escaping will need such
functionality. Like you might want *.ftlh to be automatically HTML
escaped, but not for *.ftl. (That's something I ran into recently,
though I have used Velocity there...)
So I came up with TemplateConfigurer, which is an object on which you
can set settings (from freemarker.core.Configurable), which it can set
in Template like myTemplateCfger.configure(template). A
TemplateConfigurer can also hold settings that influence parsing (like
tag_syntax, etc., from freemarker.core.ParserConfiguration, which is
also new in 2.3.24), and can even specify the charset to used for
loading the template (if you ever had a mix of UTF-8 and
ISO-8859-<x>/CP<x> templates...).
Then, I have added a new Configuration setting, called
"templateConfigurers". It's type is
freemarker.cache.TemplateConfigurerFactory, which is basically a
collection of TemplateConfigurer-s, plus rules that tell that
depending on the name of the template (the "source name" that the
TemplateLoader uses), when to apply which. Using the Properties-based
configuration syntax of FreeMarker for brevity (the Java config would
be the same, but with bunch of `new`-s and setXxx-s), it's something
like this:
MergingTemplateConfigurerFactory(
FirstMatchTemplateConfigurerFactory(
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.de.*'),
TemplateConfigurer(timeZone=TimeZone('GMT+01'), locale=Locale('de', 'DE'))),
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.fr.*'),
TemplateConfigurer(timeZone=TimeZone('GMT'), locale=Locale('fr', 'FR'))),
allowNoMatch=true
),
FirstMatchTemplateConfigurerFactory(
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.ftlh'),
TemplateConfigurer(outputFormat='HTML')),
ConditionalTemplateConfigurerFactory(
FileNameGlobMatcher('*.ftlx'),
TemplateConfigurer(outputFormat='XML')),
noMatchErrorDetails='Unrecognized template file extension'
),
ConditionalTemplateConfigurerFactory(
PathGlobMatcher('stat/**')
TemplateConfigurer(timeZone=TimeZone('UTC'))
)
)
The "outputFormat" setting above is hypothetical, we don't yet have
it.
So if you set this as the "templateConfigurers", and you get a
template called "foo.de.ftlh", then that Template will have locale
de_DE, time zone GMT+01 and outoutFormat (again, hypothetical) "HTML".
For "stats/foo.de.ftlh" the time zone will be UTC instead (because
when merging, the last setting value assignment wins).
So that's it. Opinions, ideas?
--
Best regards,
Daniel Dekany
------------------------------------------------------------------------------
Best regards,
Daniel Dekany
------------------------------------------------------------------------------