package org.docbag.template.transformer.velocity; import java.io.CharArrayWriter; import java.util.Set; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.docbag.Context; import org.docbag.DefaultContext; import org.docbag.stream.MemoryInputStream; import org.docbag.template.DocumentTemplateStream; import org.docbag.template.MemoryTemplateStream; import org.docbag.template.transformer.TemplateTransformer; import org.docbag.template.transformer.xslt.DefaultXSLTTemplateTransformer; /** * VelocityTemplateTransformer can be used as a "pre transformer" to the actual transformation process. * <p>It uses <a href="http://velocity.apache.org/">Velocity</a>, a great Java template engine, to pre-process * the templates and applies all it's templating rules.</p> * <p>Usage of VelocityTemplateTransformer requires one extra read \ parse step of the {@link DocumentTemplateStream} * which makes the {@link org.docbag.Document} creation process a bit slower.</p> * * @author Jakub Torbicki */ public class VelocityTemplateTransformer implements TemplateTransformer<DocumentTemplateStream> { private volatile boolean ready = false; private final VelocityEngine ve = new VelocityEngine(); private final ThreadAwareTemplateResourceLoader resourceLoader = new ThreadAwareTemplateResourceLoader(); private final TemplateTransformer<DocumentTemplateStream> transformer; public VelocityTemplateTransformer() { this(new DefaultXSLTTemplateTransformer()); } public VelocityTemplateTransformer(TemplateTransformer<DocumentTemplateStream> transformer) { this.transformer = transformer; initVelocity(); } @Override public DocumentTemplateStream transform(DocumentTemplateStream templateStream) { return transform(templateStream, new DefaultContext()); } @Override public DocumentTemplateStream transform(DocumentTemplateStream templateStream, Context context) { String templateName = templateStream.getName(); VelocityContext velocityContext = createVelocityContext(context); CharArrayWriter writer = new CharArrayWriter(); resourceLoader.putResource(templateStream); try { ve.mergeTemplate(templateName, "UTF-8", velocityContext, writer); MemoryTemplateStream velocityStream = new MemoryTemplateStream(new MemoryInputStream(writer.toString().getBytes()), templateName); return transformer.transform(velocityStream, context); } finally { resourceLoader.clearResource(); } } private VelocityContext createVelocityContext(Context<String, Object> context) { VelocityContext velocityContext = new VelocityContext(); Set<String> keys = context.keys(); for (String key : keys) { velocityContext.put(key, context.get(key)); } return velocityContext; } private void initVelocity() { if (!ready) { synchronized (ve) { if (!ready) { ve.setProperty("resource.loader", "docbag, file"); ve.setProperty("docbag.resource.loader.description", "Docbag Resource Loader For Velocity"); ve.setProperty("docbag.resource.loader.instance", resourceLoader); ve.setProperty("docbag.resource.loader.cache", "false"); ve.setProperty("docbag.resource.loader.modificationCheckInterval", "0"); ve.init(); ready = true; } } } } }