The following is an example of a ResouceLoader that uses an EntityManager and NamedQuery to retrieve templates:
package mysite.velocity; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.InputStream; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.NoResultException; import javax.persistence.Query; import org.apache.commons.collections.ExtendedProperties; import org.apache.commons.lang.StringUtils; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.resource.Resource; import org.apache.velocity.runtime.resource.loader.ResourceLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * JPA EntityManager ResourceLoader implementation. * * @author David Pedowitz * */ public class EntityManagerResourceLoader extends ResourceLoader { private static final Logger LOGGER = LoggerFactory .getLogger(EntityManagerResourceLoader.class); private EntityManagerFactory entityManagerFactory; private String templateNamedQuery; public void init(ExtendedProperties configuration) { templateNamedQuery = StringUtils.trimToNull(configuration .getString("resource.templateNamedQuery")); if (templateNamedQuery == null) { throw new RuntimeException("No templateNamedQuery defined."); } else if (entityManagerFactory == null) { throw new RuntimeException("No entityManagerFactory defined."); } LOGGER.debug("Configured entity manager resource loader with " + "templateNamedQuery:{} and entityManagerFactory:{}", templateNamedQuery, entityManagerFactory); } public long getLastModified(Resource resource) { return 0; } public InputStream getResourceStream(String name) throws ResourceNotFoundException { LOGGER.debug("Retreive resource for name:{}", name); EntityManager entityManager = entityManagerFactory .createEntityManager(); try { Query query = entityManager.createNamedQuery(templateNamedQuery); query.setParameter(1, name); String template = (String) query.getSingleResult(); return new BufferedInputStream(new ByteArrayInputStream(template .getBytes())); } catch (NoResultException ex) { throw new ResourceNotFoundException("No resource found for name:" + name); } finally { entityManager.close(); } } public boolean isSourceModified(Resource resource) { return false; } public void setEntityManagerFactory( EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; } }
I used Spring to configure the VelocityEngine and ResourceLoader like so:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd"> ... contents omitted ... <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="velocityPropertiesMap"> <map> <entry key="resource.loader" value="em" /> <entry key="em.resource.loader.instance" value-ref="entityManagerResourceLoader" /> <entry key="em.resource.loader.resource.templateNamedQuery" value="findEmailTemplateBodyByName" /> </map> </property> </bean> <bean id="entityManagerResourceLoader" class="mysite.velocity.EntityManagerResourceLoader" p:entityManagerFactory-ref="entityManagerFactory" /> </beans>
Enjoy!