Spring Modules support for template engines is excellent.
The code base is organized into the following packages with nice abstraction.
1) Providers
2) Sources
3) Resolvers
4) Support
Providers: Supports Freemarker, Velocity, Groovy, Stemp, Webmacro and XSLT template engines.
Sources: Template as String, as File and Spring Resource.
Resolvers: Bunch of resolvers to resolve the template.
Support: Template and TemplateSet support classes.
Here is the class which I wrote to support RegularExpression based resolvers.
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ascendant.template.resolvers;
import java.io.IOException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springmodules.template.TemplateSource;
import org.springmodules.template.TemplateSourceResolver;
import org.springmodules.template.sources.ResourceTemplateSource;
/**
* A TemplateSourceResolver based on
*
* @author Ramesh Mandaleeka
*/
public class PathMatchingTemplateSourcePatternResolver implements TemplateSourceResolver, InitializingBean {
private String locationPattern;
private PathMatchingResourcePatternResolver resolver;
/**
* Default constructor (javabean support).
*/
public PathMatchingTemplateSourcePatternResolver() {
resolver = new PathMatchingResourcePatternResolver();
}
public PathMatchingTemplateSourcePatternResolver(String locationPattern) {
this.locationPattern = locationPattern;
resolver = new PathMatchingResourcePatternResolver();
}
public void afterPropertiesSet() throws Exception {
if ( locationPattern == null || "".equals(locationPattern)) {
throw new Exception("Required property 'locationPattern' is not set");
}
}
public final TemplateSource resolveTemplateSource(String name) {
TemplateSource templateSource = null;
if ( name == null || "".equals(name)) {
templateSource = null;
} else {
// Do I need to check 'locationPattern' is null or not? nah!
try {
Resource[] resources = resolver.getResources(locationPattern);
for (int counter = 0; counter < resources.length; counter++) {
if ( name.equals(resources[counter].getFilename())) {
templateSource = new ResourceTemplateSource(resources[counter]);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return templateSource;
}
//============================================== Setter/Getter =====================================================
public String getLocationPattern() {
return locationPattern;
}
public void setLocationPattern(String locationPattern) {
this.locationPattern = locationPattern;
}
}
The config file:
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<bean id="pathMatchingTemplateSourcePatternResolver"
class="org.springmodules.template.resolvers.PathMatchingTemplateSourcePatternResolver">
<property name="locationPattern" value="classpath*:*.ftl"></property>
</bean>
</beans>
The Client class:
package com.ascendant.templates;
//~--- non-JDK imports --------------------------------------------------------
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springmodules.template.Template;
import org.springmodules.template.TemplateSet;
import org.springmodules.template.providers.freemarker.FreemarkerTemplateSetFactoryBean;
import org.springmodules.template.resolvers.PathMatchingTemplateSourcePatternResolver;
public class App {
public static void main(String[] args) {
try {
// Prepare properties
Properties p = new Properties();
p.put("datetime_format", "EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'");
// set properties
FreemarkerTemplateSetFactoryBean ftsfBean = new FreemarkerTemplateSetFactoryBean();
ftsfBean.setSettings(p);
// reuse true
ftsfBean.setReuseTemplateSet(true);
// get template file as Resource
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/com/sonybmg/applicationContext.xml");
ftsfBean.setTemplateSourceResolver((PathMatchingTemplateSourcePatternResolver)applicationContext.getBean("pathMatchingTemplateSourcePatternResolver"));
ftsfBean.afterPropertiesSet();
TemplateSet ts = (TemplateSet) ftsfBean.getObject();
Template t = ts.getTemplate("test.ftl");
// Build the data-model
Map root = new HashMap();
root.put("message", "Hello World!");
root.put("date", new Date());
System.out.println(t.generate(root));
} catch (Exception e) {
e.printStackTrace();
}
}
}
test.ftl
<html>
<head>
<title>FreeMarker Example Web Application 1</title>
</head>
<body>
${message} ${date?datetime}
</body>
</html>