1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.freemarker;
35
36 import freemarker.cache.TemplateLoader;
37 import freemarker.ext.jsp.TaglibFactory;
38 import freemarker.ext.servlet.FreemarkerServlet;
39 import freemarker.ext.servlet.HttpRequestHashModel;
40 import freemarker.ext.servlet.ServletContextHashModel;
41 import freemarker.template.Configuration;
42 import freemarker.template.ObjectWrapper;
43 import freemarker.template.Template;
44 import freemarker.template.TemplateException;
45 import freemarker.template.TemplateModel;
46 import freemarker.template.TemplateModelException;
47 import info.magnolia.cms.beans.config.ServerConfiguration;
48 import info.magnolia.context.MgnlContext;
49 import info.magnolia.context.WebContext;
50 import info.magnolia.objectfactory.Components;
51
52 import javax.servlet.GenericServlet;
53 import javax.servlet.ServletContext;
54 import javax.servlet.ServletException;
55 import java.io.IOException;
56 import java.io.Reader;
57 import java.io.Writer;
58 import java.util.Locale;
59 import java.util.Map;
60 import java.util.Set;
61
62
63
64
65
66
67
68
69
70
71 public class FreemarkerHelper {
72
73 public static FreemarkerHelper getInstance() {
74 return Components.getSingleton(FreemarkerHelper.class);
75 }
76
77 private final Configuration cfg;
78
79
80 private TaglibFactory taglibFactory;
81 private ServletContextHashModel servletContextHashModel;
82
83 public FreemarkerHelper() {
84 this(Components.getSingleton(FreemarkerConfig.class));
85 }
86
87 public FreemarkerHelper(final FreemarkerConfig freemarkerConfig) {
88
89 this.cfg = new Configuration() {
90 @Override
91 public Set getSharedVariableNames() {
92 final Set names = super.getSharedVariableNames();
93 names.addAll(freemarkerConfig.getSharedVariables().keySet());
94 return names;
95 }
96
97 @Override
98 public TemplateModel getSharedVariable(String name) {
99 final TemplateModel value = super.getSharedVariable(name);
100 if (value==null) {
101 return freemarkerConfig.getSharedVariables().get(name);
102 }
103 return value;
104 }
105 };
106 cfg.setTemplateExceptionHandler(freemarkerConfig.getTemplateExceptionHandler());
107
108
109
110
111 cfg.setTemplateLoader(new ConfigDelegatingTemplateLoader(freemarkerConfig));
112 cfg.setObjectWrapper(new ConfigDelegatingObjectWrapper(freemarkerConfig));
113
114 cfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);
115 cfg.setDefaultEncoding("UTF8");
116
117 }
118
119
120
121
122 public void resetObjectWrapper() {
123
124 }
125
126
127
128
129 public void render(String templatePath, Object root, Writer out) throws TemplateException, IOException {
130 render(templatePath, null, null, root, out);
131 }
132
133
134
135
136
137
138
139
140
141
142
143 public void render(String templatePath, Locale locale, String i18nBasename, Object root, Writer out) throws TemplateException, IOException {
144 final Locale localeToUse = checkLocale(locale);
145 prepareRendering(localeToUse, i18nBasename, root);
146
147 final Template template = cfg.getTemplate(templatePath, localeToUse);
148 template.process(root, out);
149 }
150
151
152
153
154
155
156
157 public void render(Reader template, Object root, Writer out) throws TemplateException, IOException {
158 render(template, null, null, root, out);
159 }
160
161 protected void render(Reader template, Locale locale, String i18nBasename, Object root, Writer out) throws TemplateException, IOException {
162 final Locale localeToUse = checkLocale(locale);
163 prepareRendering(localeToUse, i18nBasename, root);
164
165 final Template t = new Template("inlinetemplate", template, cfg);
166 t.setLocale(localeToUse);
167 t.process(root, out);
168 }
169
170
171
172
173 protected Locale checkLocale(Locale locale) {
174 if (locale != null) {
175 return locale;
176 } else if (MgnlContext.hasInstance()) {
177 return MgnlContext.getLocale();
178 } else {
179 return Locale.getDefault();
180 }
181 }
182
183
184
185
186 protected void prepareRendering(Locale checkedLocale, String i18nBasename, Object root) {
187 if (root instanceof Map) {
188 final Map<String, Object> data = (Map<String, Object>) root;
189 addDefaultData(data, checkedLocale, i18nBasename);
190 }
191 }
192
193 protected void addDefaultData(Map<String, Object> data, Locale locale, String i18nBasename) {
194 if (MgnlContext.hasInstance()) {
195 data.put("ctx", MgnlContext.getInstance());
196 }
197 if (MgnlContext.isWebContext()) {
198 final WebContext webCtx = MgnlContext.getWebContext();
199
200 data.put("contextPath", webCtx.getContextPath());
201 data.put("aggregationState", webCtx.getAggregationState());
202
203 addTaglibSupportData(data, webCtx);
204 }
205
206 data.put("defaultBaseUrl", ServerConfiguration.getInstance().getDefaultBaseUrl());
207
208 if (i18nBasename != null) {
209 data.put("i18n", new MessagesWrapper(i18nBasename, locale));
210 }
211
212
213
214
215
216
217
218 }
219
220 protected void addTaglibSupportData(Map<String, Object> data, WebContext webCtx) {
221 final ServletContext servletContext = webCtx.getServletContext();
222 try {
223 data.put(FreemarkerServlet.KEY_JSP_TAGLIBS, checkTaglibFactory(servletContext));
224 data.put(FreemarkerServlet.KEY_APPLICATION_PRIVATE, checkServletContextModel(servletContext));
225 data.put(FreemarkerServlet.KEY_REQUEST_PRIVATE, new HttpRequestHashModel(webCtx.getRequest(), cfg.getObjectWrapper()));
226 } catch (ServletException e) {
227
228 throw new RuntimeException("Can't initialize taglib support for FreeMarker: ", e);
229 }
230 }
231
232 protected TaglibFactory checkTaglibFactory(ServletContext servletContext) {
233 if (taglibFactory == null) {
234 taglibFactory = new TaglibFactory(servletContext);
235 }
236 return taglibFactory;
237 }
238
239 protected ServletContextHashModel checkServletContextModel(ServletContext servletContext) throws ServletException {
240 if (servletContextHashModel == null) {
241
242 final GenericServlet fs = new DoNothingServlet(servletContext);
243 servletContextHashModel = new ServletContextHashModel(fs, cfg.getObjectWrapper());
244 }
245 return servletContextHashModel;
246 }
247
248 protected Configuration getConfiguration() {
249 return cfg;
250 }
251
252 private class ConfigDelegatingTemplateLoader implements TemplateLoader {
253 private final FreemarkerConfig freemarkerConfig;
254
255 public ConfigDelegatingTemplateLoader(FreemarkerConfig freemarkerConfig) {
256 this.freemarkerConfig = freemarkerConfig;
257 }
258
259 public Object findTemplateSource(String name) throws IOException {
260 return freemarkerConfig.getTemplateLoader().findTemplateSource(name);
261 }
262
263 public long getLastModified(Object templateSource) {
264 return freemarkerConfig.getTemplateLoader().getLastModified(templateSource);
265 }
266
267 public Reader getReader(Object templateSource, String encoding) throws IOException {
268 return freemarkerConfig.getTemplateLoader().getReader(templateSource, encoding);
269 }
270
271 public void closeTemplateSource(Object templateSource) throws IOException {
272 freemarkerConfig.getTemplateLoader().closeTemplateSource(templateSource);
273 }
274 }
275
276 private class ConfigDelegatingObjectWrapper implements ObjectWrapper {
277 private final FreemarkerConfig freemarkerConfig;
278
279 public ConfigDelegatingObjectWrapper(FreemarkerConfig freemarkerConfig) {
280 this.freemarkerConfig = freemarkerConfig;
281 }
282
283 public TemplateModel wrap(Object obj) throws TemplateModelException {
284 return freemarkerConfig.getObjectWrapper().wrap(obj);
285 }
286 }
287 }