Using stringtemplate with Karaf

Monday, September 17th 2012, 5:33 pm

For building this site I decided to use StringTemplate as the templating engine for all the HTML that is generated and sent to the browser. The philosophy behind StringTemplate really resonates with me, it stresses complete separation of logic and presentation: something that I have found to be really important in order to keep code clean. In other projects I have used Wicket and the complete separation of layout and code is one of the things I liked the most about this framework. However Wicket can also be heavy and needs a lot of care regarding session state, while generating really ugly URLs by default. Hence my choice for a simpler templating engine with a simpler philosophy: StringTemplate.

My adventure in using StringTemplate started with some problems, the first one, was that it was not OSGi friendly. For this website I am running Jetty on top of Karaf. Karaf is a nice OSGi runtime environment that allows me to quickly develop and test applications. I have found its ability to redeploy new bundles a real productivity boost. So when I decided to use StringTemplate, my first attempt was to load StringTemplate into Karaf from the default Maven repository. I did so with the following command:

karaf@root>install mvn:org.antlr.ST4/4.0.4
karaf@root>list
[3592] [Installed  ] [            ] [       ] [   60] mvn:org.antlr/ST4/4.0.4

Immediately I could see that the ST4 jar did not have a proper MANIFEST.MF, hence the weird bundle name ("mvn:org.antlr/ST4/4.0.4"). However Karaf can enable the use of non-OSGi friendly jars, through the wrap command, so I decided to give it a go. I typed the following command to OSGify StringTemplate:

karaf@root>install wrap:mvn:org.antlr.ST4/4.0.4
karaf@root>list
[3593] [Installed  ] [            ] [       ] [   60] wrap_mvn_org.antlr_ST4_4.0.4 (0)

The bundle name still looked kind of weird, but Karaf did the best it could to turn StringTemplate into a proper bundle, StringTemplate could now be used in an OSGi environment. Then came my second stumbling block: StringTemplate depends on ANTLR which also is not OSGi friendly. Again I had to use the same "wrap:" trick:

karaf@root>install wrap:org.antlr/antlr-runtime/3.3
karaf@root>list
[3593] [Resolved     ] [            ] [       ] [   60] wrap_mvn_org.antlr_ST4_4.0.4 (0)
[3594] [Resolved     ] [            ] [       ] [   60] wrap_mvn_org.antlr_antlr-runtime_3.3 (0)

Things were looking better. It seems I was able to finally start the bundles and use them in my project. I started the bundles and tried to use them in my project with the following code:

STGroup templates = new STGroupDir("pages", "UTF-8", '$', '$');

However StringTemplate was unable to find my templates, it was saying that the templates did not exist! After much looking around and examining StringTemplate's code I found the culprit: StringTemplate tries to dynamically read the classpath in order to find the proper file that contains the template. To do this, it tries to open several variations of a file that could contain the template with the URL.openStream method, if the method returns FileNotFoundException StringTemplate assumes it has not found the file and continues looking, however if the method returns IOException, StringTemplate assumes that something is wrong with storage itself and it stops looking. This works perfectly in a non-OSGi environment, unfortunately in OSGi this behavior is not reliable.

Felix, which is the default underlying OSGi kernel behind Karaf, will throw an IOException if the file that StringTemplate is looking for is not found, and will break StringTemplate's algorithm. Luckily, even though Felix is the default OSGi implementation in Karaf, Karaf is also capable of using Equinox, an implementation from the Eclipse group. As chance would have it, Equinox does throw a FileNotFoundException instead of a IOException when the file is not found, thus, if you make Karaf use Equinox instead of Felix, StringTemplate will work correctly. The way to perform this change is through editing the file ${karaf.dir}/etc/config.properties and change the line that points to felix for the following:

#
# Framework selection properties
#
karaf.framework=equinox

Restart Karaf, and now you should be able to use StringTemplate properly

I brought this issue up in the Felix mailing list, hoping for a change that would enable me to use StringTemplate under Felix. The Felix developers were very open and asked me to open a Jira issue in order to create discussion on this topic. Hopefuly a consensus can be reached, both Felix and Equinox's behaviour will be consistent and StringTemplate will finally be usable under both environments. The issue that was opened can be seen in Felix's JIRA under issue FELIX-3342. For the meantime, if you want to use StringTemplate under Karaf, you will have to pick Equinox as your OSGi implementation.

comments powered byDisqus