1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.springframework.extensions.webscripts.processor;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.StringReader;
24 import java.io.Writer;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.springframework.extensions.webscripts.WebScriptException;
29
30 import freemarker.cache.MruCacheStorage;
31 import freemarker.template.Configuration;
32 import freemarker.template.Template;
33 import freemarker.template.TemplateExceptionHandler;
34
35
36
37
38
39
40
41 public class FTLTemplateProcessor extends AbstractTemplateProcessor
42 {
43 private static final Log logger = LogFactory.getLog(FTLTemplateProcessor.class);
44
45
46 private String defaultEncoding;
47
48
49 private Configuration templateConfig;
50
51
52 private Configuration stringConfig;
53
54
55 private int updateDelay = 0;
56
57
58 private int cacheSize = 256;
59
60
61
62
63 public void setDefaultEncoding(String defaultEncoding)
64 {
65 this.defaultEncoding = defaultEncoding;
66 }
67
68
69
70
71 public String getDefaultEncoding()
72 {
73 return this.defaultEncoding;
74 }
75
76
77
78
79 public void setUpdateDelay(int updateDelay)
80 {
81 this.updateDelay = updateDelay;
82 }
83
84
85
86
87 public void setCacheSize(int cacheSize)
88 {
89 if (cacheSize >= 0)
90 {
91 this.cacheSize = cacheSize;
92 }
93 }
94
95
96
97
98 public void init()
99 {
100 super.init();
101
102 this.initConfig();
103 }
104
105
106
107
108 public String getExtension()
109 {
110 return "ftl";
111 }
112
113
114
115
116 public String getName()
117 {
118 return "freemarker";
119 }
120
121
122
123
124 public void process(String template, Object model, Writer out)
125 {
126 if (template == null || template.length() == 0)
127 {
128 throw new IllegalArgumentException("Template name is mandatory.");
129 }
130 if (model == null)
131 {
132 throw new IllegalArgumentException("Model is mandatory.");
133 }
134 if (out == null)
135 {
136 throw new IllegalArgumentException("Output Writer is mandatory.");
137 }
138
139 try
140 {
141 long startTime = 0;
142 if (logger.isDebugEnabled())
143 {
144 logger.debug("Executing template: " + template);
145 startTime = System.nanoTime();
146 }
147
148 addProcessorModelExtensions(model);
149
150 Template t = templateConfig.getTemplate(template);
151 if (t != null)
152 {
153 try
154 {
155
156 t.process(model, out);
157 }
158 catch (Throwable err)
159 {
160 throw new WebScriptException("Failed to process template " + template, err);
161 }
162 }
163 else
164 {
165 throw new WebScriptException("Cannot find template " + template);
166 }
167
168 if (logger.isDebugEnabled())
169 {
170 long endTime = System.nanoTime();
171 logger.debug("Time to execute template: " + (endTime - startTime)/1000000f + "ms");
172 }
173 }
174 catch (IOException ioerr)
175 {
176 throw new WebScriptException("Failed to process template " + template, ioerr);
177 }
178 }
179
180
181
182
183 public void processString(String template, Object model, Writer out)
184 {
185 if (template == null || template.length() == 0)
186 {
187 throw new IllegalArgumentException("Template is mandatory.");
188 }
189 if (model == null)
190 {
191 throw new IllegalArgumentException("Model is mandatory.");
192 }
193 if (out == null)
194 {
195 throw new IllegalArgumentException("Output Writer is mandatory.");
196 }
197
198 long startTime = 0;
199 if (logger.isDebugEnabled())
200 {
201 logger.debug("Executing template: " + template);
202 startTime = System.nanoTime();
203 }
204
205 addProcessorModelExtensions(model);
206
207 try
208 {
209 Template t = new Template("name", new StringReader(template), stringConfig);
210 t.process(model, out);
211
212 if (logger.isDebugEnabled())
213 {
214 long endTime = System.nanoTime();
215 logger.debug("Time to execute template: " + (endTime - startTime)/1000000f + "ms");
216 }
217 }
218 catch (Throwable err)
219 {
220 throw new WebScriptException("Failed to process template " + template, err);
221 }
222 }
223
224
225
226
227 public void reset()
228 {
229 this.init();
230
231 if (templateConfig != null)
232 {
233 templateConfig.clearTemplateCache();
234 }
235 }
236
237
238
239
240 public boolean hasTemplate(String templatePath)
241 {
242 boolean hasTemplate = false;
243 try
244 {
245 Template template = templateConfig.getTemplate(templatePath);
246 hasTemplate = (template != null);
247 }
248 catch(FileNotFoundException e)
249 {
250
251 }
252 catch(IOException e)
253 {
254 throw new WebScriptException("Failed to retrieve template " + templatePath, e);
255 }
256 return hasTemplate;
257 }
258
259
260
261
262 protected void initConfig()
263 {
264
265 Configuration config = new Configuration();
266 config.setCacheStorage(new MruCacheStorage(cacheSize, cacheSize << 1));
267 config.setTemplateUpdateDelay(updateDelay);
268 config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
269 config.setLocalizedLookup(false);
270 config.setOutputEncoding("UTF-8");
271 if (defaultEncoding != null)
272 {
273 config.setDefaultEncoding(defaultEncoding);
274 }
275
276 if (getTemplateLoader() != null)
277 {
278 config.setTemplateLoader(getTemplateLoader());
279 }
280
281 templateConfig = config;
282
283
284 stringConfig = new Configuration();
285 stringConfig.setCacheStorage(new MruCacheStorage(2, 0));
286 stringConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
287 stringConfig.setOutputEncoding("UTF-8");
288 if (defaultEncoding != null)
289 {
290 stringConfig.setDefaultEncoding(defaultEncoding);
291 }
292 }
293 }