This was a tricky question - indeed. Required me to go through the implementation of the source files in org.restlet.ext.Freemarker package - Phew!
Here's how you can do it
If you need to create your OWN Configuration Object, set the 'templateLoader' to use and then have TemplateRepresentation 'work' on it for rendering:
Configuration cfg = new Configuration();
ContextTemplateLoader loader = new ContextTemplateLoader(getContext(),"war:///WEB-INF");
cfg.setTemplateLoader(loader);
TemplateRepresentation rep = null;
Mail mail = new Mail(); //The data object you wish to populate - example from Restlet itself
mail.setStatus("received");
mail.setSubject("Message to self");
mail.setContent("Doh!");
mail.setAccountRef(new Reference(getReference(), "..").getTargetRef()
.toString());
Map<String, Object> data = new HashMap<String, Object>();
data.put("status", mail.getStatus());
data.put("subject", mail.getSubject());
data.put("content", mail.getContent());
data.put("accountRef", mail.getAccountRef());
rep = new TemplateRepresentation("Mail.ftl", cfg, data, MediaType.TEXT_HTML);
return rep;
If you are happy with the default and wish to use a class loader based way of loading the templates
//Load the FreeMarker template
Representation mailFtl = new ClientResource(
LocalReference.createClapReference(getClass().getPackage())
+ "/Mail.ftl").get();
//Wraps the bean with a FreeMarker representation
return new TemplateRepresentation(mailFtl, mail, MediaType.TEXT_HTML);
If you want to initialize the Configuration Object once and set the template by calling the setServletContextForTemplateLoading(...) method on the configuration object. You could always do this in a ServletContextListener
public class Config implements ServletContextListener {
private static Configuration cfg = new Configuration();
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
cfg.setServletContextForTemplateLoading(sc, "/WEB-INF");
}
public static Configuration getFMConfig()
{
return cfg;
}
}
And then call the static getFMConfig() and pass it to TemplateRepresentation as in 1
Things to note:
- If you do get a protocol not supported Exception it'll be in case 2. Implies that the ServerResource doesn't know what protocol to use to access the file - It'll be the CLAP protocol of Restlet. You may have to set up the init-params for RestletServlet in the web.xml file and have CLAP as one of the param-values
- The TemplateRepresentation has quite a few constructors - if you DON'T pass in a configuration object during instantiation (using another overloaded constructor), it will create a new Configuration() for you. So you don't have to do any configuration set up as in 2 (This may strike you as obvious but I assumed that you WOULD still need to set a configuration or it would 'pick it up from somewhere')
- If you DO wish to have your OWN configuration setup you MUST pass it to one of the constructors
- Have a look at the "war:///" string in the constructor of ContextTemplateLoader in 1. this is important No where is it mentioned what this baseUri reference should be, not even in the docs. I tried for quite a while before figuring it out that it should be "war:///" followed by the folder name where the templates are stored.
- For case 2 you'll probably have to store the templates in the same package as the class file from where this code is accessed. If you see carefully you'll notice a LocalReference parameter as an argument to ClientResource saying that the resource is supposed to be locally present and thus you need to use the custom CLAP protocol (classLoader Access Protocol)
Personal Frustration point - why isn't all this even clarified in the documentation or ANYWHERE :)
Hope it helps someone who stumbles upon this post! Phew!