Categories
Java

velocity with custom loader

Velocity is a feature rich template engine for Java applications. This engine is mainly designed to have template files which then will be rendered into OutputStreams using a context. But you can also extend velocity to use in memory or database stored templates.

First you have to register your own ResourceLoader at the VelocityEngine:

final VelocityEngine ve = new VelocityEngine();
ve.setProperty("yamltemplates.resource.loader.class", YamlTemplateResourceLoader.class.getName());
ve.setProperty("yamltemplates.resource.loader.templatefile", templateFile);
ve.setProperty(VelocityEngine.RESOURCE_LOADER, "yamltemplates");
ve.setProperty(VelocityEngine.INPUT_ENCODING, "UTF-8");
ve.init();

Then you can implement your ResourceLoader:

public class YamlTemplateResourceLoader extends ResourceLoader {

    private Map<String, Object> templateData;

    @Override
    public void init(final ExtProperties configuration)
    {
        try
        {
            try (InputStream data = (InputStream) configuration.get("templatefile"))
            {
                Yaml yaml = new Yaml();
                templateData = yaml.load(data);
            }
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Reader getResourceReader(final String source, final String encoding) throws ResourceNotFoundException
    {
        try
        {
            if ("velocimacros.vtl".equals(source))
            {
                return buildReader(new ByteArrayInputStream(new byte[0]), encoding);
            }
            Object template = templateData.get(source);
            if (template == null)
            {
                throw new ResourceNotFoundException(source);
            }
            if (template instanceof String)
            {
                return new StringReader((String) template);
            }
            throw new RuntimeException("cannot handle " + template);
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean isSourceModified(final Resource resource)
    {
        return false;
    }

    @Override
    public long getLastModified(final Resource resource)
    {
        return 0;
    }
}

Last but not least you can render your templates like any other templates with Velocity:

StringWriter stringWriter = new StringWriter();
VelocityContext context = new VelocityContext();
context.put("myparam", "Hello World!");
contextSetup.setupContext(context);
ve.getTemplate(templateName).merge(context, stringWriter);
String result = stringWriter.toString();

}