Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Velocity in OSGi: how to load templates from classpath

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'

like image 788
user1109578 Avatar asked Dec 22 '11 11:12

user1109578


2 Answers

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.

like image 136
Balazs Zsoldos Avatar answered Oct 16 '22 22:10

Balazs Zsoldos


Two things to verify

1. Classpath issues

Make sure you set the classpath of the OSGi bundle via the MANIFEST.MF to include a dot:

Bundle-ClassPath: .

The dot means to include the root of the bundle in the class-loading hierarchy, where your folder "velocitytemplates" likely resides.

And you need to have the Velocity jar-files in the same bundle where your template-files reside, because otherwise you'll get classloading issues as Velocity would reside in a different bundle and thus would not see the "velocitytemplates" at all in its classpath.

2. There is no "path" for ClasspathResourceLoader

ClasspathResourceLoader does not support setting a "path", as it uses the Classpath by definition, so either add "velocitytemplates" to the Classpath in the OSGi bundle (MANIFESt.MF) or reference the velocity templates with complete path, i.e. "velocitytemplates/index.vm"

like image 23
centic Avatar answered Oct 17 '22 00:10

centic