Velocity in OSGi: how to load templates from classpath

user1109578 picture user1109578 · Dec 22, 2011 · Viewed 7.1k times · Source

I am developing an application for OSGi with velocity template engine. It works great for loading my templates by file loader but now I have to implement this templates in my jar and load it as resources.

How can i made it work?

My Code:

ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", 
    ClasspathResourceLoader.class.getName());
ve.setProperty("classpath.resource.loader.path", "/velocitytemplates");
ve.init();

ve.getTemplate("foo.vm");

This will throw an exception like

Unable to find resource 'index.vm'

Caused by:

org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'index.vm'

Answer

Balazs Zsoldos picture Balazs Zsoldos · Jul 11, 2012

Sadly Velocity is not that OSGi friendly. Therefore you cannot use the built in ClasspathResourceLoader and it is hard to add a custom developed ResourceLoader as well.

I suggest that you should get your template as a Reader in any of the ordinary ways and choose one of the following:

  • Use the VelocityEngine evaulate function if you need to merge the template rarely (performance does not matter that much)
  • Create a Template by hand with the inner classes of Velocity

The first option can be used if you do not have to merge your templates very often so performance is not a key requirement.

Here is a sample for the second option where the created template object can be reused by calling the merge function on it (expecting that you already got a Reader to your vm file or resource):

RuntimeInstance runtimeInstance = new RuntimeInstance();
runtimeInstance.init();
SimpleNode simpleNode = runtimeInstance.parse(reader, "nameOfYourTemplateResource");

Template template = new Template();
simpleNode.init(new InternalContextAdapterImpl(new VelocityContext()), runtimeInstance);
template.setData(simpleNode);

template.merge(...);
...

To get a reader for the vm file in OSGi you should choose a class that is surely in the same bundle as your vm resource and call SameBundleClass.class.getResourceAsStream... You can transform your stream to writer with InputStreamReader than.

Please note that the example misses some try-catch-finally block.