Paul
Paul

Reputation: 23

Apache Velocity 1.7 cannot find templates, but only when deployed on linux

We are in the process of upgrading our Spring Application from Spring 4 to Spring 5, and so far everything is working well, except that we use Apache Velocity to build emails from templates that get sent to users based on certain activities within the application. Spring 5 removed Velocity support, so we're using the Velocity 1.7 jar from Apache instead. I have a local tomcat server running from the command line under Windows 10, and Velocity successfully finds its templates and builds the email from said templates. However, when the very same application is deployed to tomcat running on an Amazon linux server, Velocity cannot find its templates!

All templates live in WEB-INF/classes. There is a velocity.properties file in that folder, and Velocity DOES find it, as it configures the Velocity logger to log to Log4j.

The contents of that velocity.properties file:

runtime.log.logsystem.class=org.apache.velocity.runtime.log.SimpleLog4JLogSystem
runtime.log.logsystem.log4j.category=velocity

The properties I pass to Velocity from inside my applicationContext-service.xml file:

<util:properties id="velocityProperties">
    <prop key="resource.loader">class</prop>
    <prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
    <prop key="input.encoding">UTF-8</prop>
    <prop key="output.encoding">UTF-8</prop>
</util:properties>

<bean id="velocityEngine" class="org.apache.velocity.app.VelocityEngine">
    <constructor-arg ref="velocityProperties" />
</bean>

I have tried adding the actual path to my WEB-INF/classes file in the above configuration:

<util:properties id="velocityProperties">
    <prop key="resource.loader">class</prop>
    <prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
    **<prop key="class.resource.loader.path">/WEB-INF/classes</prop>**
    <prop key="input.encoding">UTF-8</prop>
    <prop key="output.encoding">UTF-8</prop>
</util:properties>

The important part of the stacktrace:

GATEWAY: ERROR 2023-06-06 21:00:00,619 [EisQuartzScheduler_Worker-2] ErrorLogger.schedulerError(2425) | Job (GATEWAY.reportProcessed.notifier.cron threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
    at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.2.1.jar:?]
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) ~[quartz-2.2.1.jar:?]
Caused by: org.springframework.scheduling.quartz.JobMethodInvocationFailedException: Invocation of method 'sendNotifications' on target class [class gov.epa.eis.util.ReportRequestProcessedNotifier] failed; nested exception is java.lang.NullPointerException
    at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:276) ~[spring-context-support-5.3.27.jar:5.3.27]
    at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.3.27.jar:5.3.27]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.2.1.jar:?]
    ... 1 more
Caused by: java.lang.NullPointerException
    at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1533) ~[velocity-1.7.jar:1.7]
    at org.apache.velocity.app.VelocityEngine.mergeTemplate(VelocityEngine.java:343) ~[velocity-1.7.jar:1.7]
    at gov.epa.eis.service.impl.MailServiceImpl.sendMessage(MailServiceImpl.java:60) ~[core-7.0.52-SNAPSHOT.jar:?]
    at gov.epa.eis.util.ReportRequestProcessedNotifier.sendNotifications(ReportRequestProcessedNotifier.java:83) ~[classes/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_362]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_362]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_362]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_362]
    at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:283) ~[spring-core-5.3.27.jar:5.3.27]
    at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:267) ~[spring-context-support-5.3.27.jar:5.3.27]
    at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.3.27.jar:5.3.27]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.2.1.jar:?]
    ... 1 more

I'm at a complete loss here...the fact that it works on my local server means that, in theory, the configuration is correct. But clearly there is something the linux server doesn't provide to Velocity that is causing this error. Any suggestions would be hugely appreciated.

Edit: As requested by PeterMmm, here is the sendMessage method:

public void setVelocityEngine(VelocityEngine velocityEngine) {
    this.velocityEngine = velocityEngine;
}

@Override
public void sendMessage(final SimpleMailMessage msg, final String templateName, final Map<String, Object> model) {
    try {
        VelocityContext context = new VelocityContext();
            
        for (String key : model.keySet()) {
            context.put(key, model.get(key));
        }
            
        StringWriter stringWriter = new StringWriter();
        velocityEngine.mergeTemplate(templateName, "UTF-8", context, stringWriter);
        final String text = stringWriter.toString();

        msg.setText(text);
        sendMessage(msg);
    } catch (VelocityException e) {
        LOG.error(e);
    }
}

Upvotes: 0

Views: 88

Answers (0)

Related Questions