Re: Configuration initialization per web request issue

Daniel Dekany <[email protected]> Sun, 10 Feb 2013 13:27:56 +0100
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Sunday, February 10, 2013, 1:11:43 PM, Albert Kam wrote:

> You get me rethinking again.
>
> So if i understand correctly, i can still use a properties file to
> hold multiple templates for a single locale.

Yes. FreeMarker doesn't assume that the templates are files, it just
passes the normalized path to the TemplateLoader, and gets back a
stream of bytes.

> My current idea is that multiple locales means multiple properties file.
> And this means that my custom template loader will have to do these :
> - be able to load the correct properties file based on the locale

This is actually a bit dirty to solve, because FreeMarker doesn't pass
the locale to the TemplateLoader, only a deduced template name like
"foo_en_US.ftl". So the TemplateLoader will have to assume that the
thing between the first "_" and ".ftl" is the locale. But I guess
that's OK...

> - get the correct template based on the passed template name
> - somehow be able to tell what template has changed within a single property file.

You don't absolutely have to do that. You can just tell that the last
modification time of a template is the same as the last modification
time of the containing file. I assume the file won't change frequently
anyway, and template parsing is quite fast actually, so who cares, if
99% of the requests are served from the cache. (It's not like with a
JSP, where re-compilation is a heavy operation.)

> For the template name, i can just use the property key as the name,
> and return the name again as the template source, and return the
> property value as the template string (as a reader instance)
> For the modification date, i can just add another
> <template-name>.last-modified property key.
> So both are fine.
>
> But i am still confused on how to get the correct localized
> properties file from template loader.
> The locale will be varied depending on my webapp's user location, so i imagine i can call :
> cfg.getTemplate(templateName, userLocale);
> I am still wondering on how to access this locale reference in the
> custom template loader in order to get the correct properties file.

Yeah, that's the dirty part... but see above.

-- 
Best regards,
 Daniel Dekany

> On Sun, Feb 10, 2013 at 6:14 PM, Daniel Dekany <[email protected]> wrote:
> Sunday, February 10, 2013, 12:07:35 PM, Albert Kam wrote:
>
>> Your reply is very helpful. I think i understand the important
>> points about caching and whether it's cachable or not. This clears
>> up about the expensiveness without caching, having to reparse everything per request.
>>
>> I just realized we can get the localized template by passing the
>> locale in the config.getTemplate(),
>> so with this, i dont need to use properties anymore.
>>
>> I will just use cfg.setDirectoryForTemplateLoading() and use
>> multiple ftl files instead of merging all into one properties file,
>> therefore having the caching feature and no need for custom
>> template loader anymore (which in my previous idea wont work well,
>> because all caches will be purged if the properties file was
>> changed, even if for just one property)
>>
>> The convinience that i will lose is everything is not inside 1 file
>> anymore like the properties file, but i think i can cope with it with some tools.
>
> I suppose this is clear, but with a custom TemplateLoader you can
> still put all the templates into the same file.
>
> --
> Best regards,
>  Daniel Dekany
>
>
>> Thank you !
>>
>> Regards from Jakarta,
>> Albert
>>
>>
>> On Sun, Feb 10, 2013 at 5:18 PM, Daniel Dekany <[email protected]> wrote:
>> Sunday, February 10, 2013, 5:58:54 AM, Albert Kam wrote:
>>
>>> I want to use freemarker's multiple StringTemplateLoader-s per each
>>> request. This means that i will have to new Configuration() per each
>>> request, right ? I wonder if this is the right way to do it, since
>>> i've read somewhere that Configuration should be initialized once
>>> per webapp because it's expensive ?
>>
>> The the biggest expense of not using a long-lived/shared Configuration
>> instance (and perhaps the only significant expense) is that you trash
>> the previously built template-cache each time you create a new
>> configuration. The template-cache stores the templates pre-parsed, so
>> when you request a template with Configuration.getTemplate(someName,
>> someLocale) for the 2nd time, FreeMarker will not load and parse it
>> again.
>>
>>> Why do i need this approach is because i want to get locale
>>> specific templates per request, which i put inside a properties
>>> file, and then fill up the templates.
>>>
>>> Example of the entry in the properties file :
>>> my.template.key1=my.freemarker.template1.here
>>> my.template.key2=my.freemarker.template2.here
>>>
>>> So the logic what i have in mind is :
>>> - i have the keys in the UI (dynamiclly obtained)
>>> - i load templates with resourcebundle depending of current user's locale
>>> - initialize configuration object
>>> - setup multiple string template loaders with those i load from
>>> resourcebundle and set them to configuration object via MultiTemplateLoader
>>> - setup the models n get the template outputs
>>> - print them onto UI response
>>>
>>> All of these can happen per web request.
>>>
>>> Is this approach appropriate ? Thank you !
>>
>> The template cache uses name+locale as the key to look up entries, so
>> just because you have different locales per request, you don't have to
>> give up caching. The problematic case is when the templates have no
>> "name" with which you can identify them, or they have but you don't
>> have a last modification time for them yet they are changing. In that
>> case you can't use the cache for *those* templates. But you can still
>> use the a common configuration, you just use `new Template(...)` to
>> create ad-hoc Template instances, instead `config.getTemplate(...)`.
>> The caveat with `new Template(...)` is that templates that are not
>> available with `config.getTemplate(...)` can't be
>> #include-ed/#import-ed in other templates.
>>
>> Of course, to use the template-cache, you need a TemplateLoader that
>> stays during the whole life-cycle of the Configuration. A
>> StringTemplateLoader that's recreated for each request won't do. So if
>> you have some custom template storage, instead of filling a
>> StringTemplateLoader each time, maybe you can implement the
>> TemplateLoader interface and then do `config.setTemplateLoader(new
>> MyResourceBundleTemplateLoader(...))` once.
>>
>> --
>> Best regards,
>>  Daniel Dekany


------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb