0

There is a ResourceLoader class in the API documentation:

https://velocity.apache.org/engine/2.0/apidocs/org/apache/velocity/runtime/resource/loader/ResourceLoader.html

I would like to implement my own loader, because I need to load templates from a database, but in a context sensitive way (in other words: DataSourceResourceLoader cannot be used, I need to write custom code to select the "right" template from the database).

It seems that ResourceLoader has some abstract methods, and it also seems that I would be able to write a custom loader by implementing these abstract methods. But I don't see any way to add a new loader to the engine. There is no "addResourceLoader" method. The documentation only shows how to configure the loaders that are built into Velocity:

https://velocity.apache.org/engine/2.0/developer-guide.html#resource-loaders

The main question: how to I add a custom resource loader to VelocityEngine (or VelocityContext?)

Another side question: I would like to turn off all built-in loaders. Especially WebappResourceLoader which is active by default, and represents a security risk in my particular application. How to do that?

nagylzs
  • 3,954
  • 6
  • 39
  • 70

2 Answers2

5

I can't answer about how to implement your own resource loader, but the second part is quite easy:

When you create the VelocityEngine, you can pass Properties that defined the "class path" of the resource loaders

The different classloaders are identified by a prefix for the property keys. So something like:

Properties props = new Properties();

// Add a default class path resource loader - just an example
props.setProperty("cp.resource.loader.class", ClasspathResourceLoader.class.getName());
props.setProperty("cp.resource.loader.cache", "true");

// Add your own resource loader
props.setProperty("db.resource.loader.class", MyDBResourceLoader.class.getName());
props.setProperty("db.resource.loader.cache", "false");

// Define the "class path" for the loaders
// in this case first the "db" loader is asked for resources, if nothing is found the "cp" loader
props.setProperty(RuntimeConstants.RESOURCE_LOADER, "db,cp");

// Now create the engine
VelocityEngine engine = new VelocityEngine(props);

The above only defines two resource loaders for that engine, no other loaders (including the default) will be used by that engine instance.

redblueflame
  • 35
  • 1
  • 11
0

You must first implement the ResourceLoader interface (or subclass an existing resource loader), then declare your resource loader in velocity.properties:

resource.loader = .... , my_loader, ...
my_loader.resource.loader.class = com.foo.MyResourceLoader
my_loader.resource.loader.some_property = some_value
... other properties...

Please note that the configuration properties syntax changed a bit in version 2.1. While the old syntax still works, if you want to avoid deprecation warnings in the log, it's rather:

resource.loaders = .... , my_loader, ...
resource.loader.my_loader.class = com.foo.MyResourceLoader
resource.loader.m_loader.some_property = some_value
... other properties...

The has ResourceLoader interface has four abstract methods that you need to provide:

  • void init(ExtProperties configuration) where the configuration object contains some_property -> some_value properties pair
  • long getLastModified(Resource resource) which returns the number of seconds since a resource has been modified
  • Reader getResourceReader(String source, String encoding) to get the actual content of thre resource
  • boolean isSourceModified(Resource resource)
Claude Brisson
  • 4,085
  • 1
  • 22
  • 30