Template loading

Page Contents

Template loaders

Template loaders are objects that load raw textual data based on abstract template paths like "index.ftl" or "products/catalog.ftl". It is up to the concrete template loader object what source does it use to fetch the requested data (files in a directory, data base, etc.). When you call cfg.getTemplate (where cfg is a Configuration instance), FreeMarker ask the template loader you have set up for the cfg to return the text for the given template path, and then FreeMarker parses that text as template.

Built-in template loaders

You can set up three template loading methods in the Configuration using the following convenience methods. (Each method will create a template loader object internally and set up the Configuration instance to use that.)

void setDirectoryForTemplateLoading(File dir);  

or

void setClassForTemplateLoading(Class cl, String prefix);  

or

void setServletContextForTemplateLoading(Object servletContext, String path);  

The first method above sets an explicit directory on the file system from which to load templates. Needless to say perhaps, the File parameter must be an existing directory. Otherwise, an exception will be thrown.

The second call takes a Class as a parameter and a prefix. This is for when you want to load templates via the same mechanism that a java ClassLoader uses to load classes. This means that the class you pass in will be used to call Class.getResource() to find the templates. The prefix parameter is prepended to the name of the template. The classloading mechanism will very likely be the preferred means of loading templates for production code, since loading from the classpath mechanism is usually more foolproof than specifying an explicit directory location on the file system. It is also nicer in a final application to keep everything in a .jar file that the user can simply execute directly and have all the icons and text and everything else inside the .jar file.

The third call takes the context of your web application, and a base path, which is interpreted relative to the web application root directory (that's the parent of the WEB-INF directory). This loader will load the templates from the web application directory. Note that we refer to "directory" here although this loading method works even for unpacked .war files since it uses ServletContext.getResource() to access the templates. If you omit the second parameter (or use ""), you can simply store the static files (.html, .jpg, etc.) mixed with the .ftl files, just .ftl files will be sent to the client processed. Of course, you must set up a Servlet for the *.ftl uri-pattern in WEB-INF/web.xml for this, otherwise the client will get the templates as is, and thus may see confidential content! You should not use empty path if this is a problem for your site, rather you should store the templates somewhere inside the WEB-INF directory, so the raw templates are never served accidentally. This mechanism will very likely be the preferred means of loading templates for servlet applications, since the templates can be updated without restarting the web application, while this often doesn't work with the class-loader mechanism.

Loading templates from multiple locations

If you need to load templates from multiple locations, you have to instantiate the template loader objects for every location, wrap them into a special template loader named MultiTemplateLoader and finally pass that loader to the setTemplateLoader(TemplateLoader loader) method of Configuration. Here's an example for loading templates from two distinct directories and with the class-loader:

import freemarker.cache.*; // template loaders live in this package

...

FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates"));
FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates"));
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "");
TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2, ctl };
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);

cfg.setTemplateLoader(mtl);  

Now FreeMarker will try to load templates from /tmp/templates directory, and if it does not find the requested template there, it will try to load that from /usr/data/templates, and if it still does not find the requested template, then it tries to load that with the class-loader.

Loading templates from other sources

If none of the built-in class loaders are good for you, you will have to write your own class that implements the freemarker.cache.TemplateLoader interface and pass it to the setTemplateLoader(TemplateLoader loader) method of Configuration. Please read the API JavaDoc for more information.

If your template source accesses the templates through an URL, you needn't implement a TemplateLoader from scratch; you can choose to subclass freemarker.cache.URLTemplateLoader instead and just implement the URL getURL(String templateName) method.

The template path

It is up to the template loader how it interprets template paths. But to work together with other components there are restrictions regarding the format of the path. In general, it is strongly recommended that template loaders use URL-style paths. The path must not use /, ./ and ../ and :// with other meaning as they have in URL paths (or in UN*X paths). The characters * and ? are reserved. Also, the template loader must not want paths starting with /; FreeMarker will never call template loader with such path. Note that FreeMarker always normalizes the paths before passing them to the template loader, so the paths do not contain /../ and such, and are relative to the imaginary template root directory.

Note that FreeMarker template loading always uses slash (not backslash) regardless of the host OS.

Template caching

FreeMarker caches templates (assuming you use the Configuration methods to create Template objects). This means that when you call getTemplate, FreeMarker not only returns the resulting Template object, but stores it in a cache, so when next time you call getTemplate with the same (or equivalent) path, it just returns the cached Template instance, and will not load and parse the template file again.

If you change the template file, then FreeMarker will re-load and re-parse the template automatically when you get the template next time. However, since checking if the file has been changed can be time consuming, there is a Configuration level setting called ``update delay''. This is the time that must elapse since the last checking for a newer version of a certain template before FreeMarker will check that again. This is set to 5 seconds by default. If you want to see the changes of templates immediately, set it to 0. Note that some template loaders may have problems with template updating. For example, class-loader based template loaders typically do not notice that you have changed the template file.

A template will be removed from the cache if you call getTemplate and FreeMarker realizes that the template file has been removed meanwhile. Also, if the JVM thinks that it begins to run out of memory, by default it can arbitrarily drop templates from the cache. Furthermore, you can empty the cache manually with the clearTemplateCache method of Configuration.

The actual strategy of when a cached template should be thrown away is pluggable with the cache_storage setting, by which you can plug any CacheStorage implementation. For most users freemarker.cache.MruCacheStorage will be sufficient. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum (strongly referenced items can't be dropped by the JVM, as opposed to softly referenced items). When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. The size of the strong and soft parts can be specified with the constructor. For example, set the size of the strong part to 20, and the size of soft part to 250:

cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))  

Or, since MruCacheStorage is the default cache storage implementation:

cfg.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250");  

When you create a new Configuration object, initially it uses an MruCacheStorage where maxStrongSize is 0, and maxSoftSize is Integer.MAX_VALUE (that is, in practice, infinite). But using non-0 maxStrongSize is maybe a better strategy for high load servers, since it seems that, with only softly referenced items, JVM tends to cause just higher resource consumption if the resource consumption was already high, because it constantly throws frequently used templates from the cache, which then have to be re-loaded and and re-parsed.

FreeMarker Manual -- For FreeMarker 2.3.20
HTML generated: 2013-06-27 20:54:33 GMT
Edited with XMLMind XML Editor
Here!