1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.freemarker;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.IOException;
20 import java.io.OutputStreamWriter;
21 import java.io.PrintWriter;
22 import java.io.StringReader;
23 import java.io.UnsupportedEncodingException;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Set;
28
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletOutputStream;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33 import javax.servlet.http.HttpServletResponseWrapper;
34
35 import org.kuali.rice.core.api.CoreApiServiceLocator;
36 import org.kuali.rice.krad.uif.UifConstants;
37 import org.kuali.rice.krad.uif.UifParameters;
38 import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
39 import org.kuali.rice.krad.uif.util.ProcessLogger;
40 import org.kuali.rice.krad.uif.util.UifRenderHelperMethods;
41 import org.kuali.rice.krad.util.GlobalVariables;
42 import org.kuali.rice.krad.util.KRADConstants;
43 import org.springframework.mock.web.MockHttpServletResponse;
44 import org.springframework.web.servlet.support.RequestContext;
45 import org.springframework.web.servlet.view.AbstractTemplateView;
46
47 import freemarker.cache.TemplateCache;
48 import freemarker.core.Environment;
49 import freemarker.core.ParseException;
50 import freemarker.ext.jsp.TaglibFactory;
51 import freemarker.ext.servlet.AllHttpScopesHashModel;
52 import freemarker.ext.servlet.FreemarkerServlet;
53 import freemarker.ext.servlet.HttpRequestHashModel;
54 import freemarker.ext.servlet.HttpRequestParametersHashModel;
55 import freemarker.ext.servlet.HttpSessionHashModel;
56 import freemarker.ext.servlet.ServletContextHashModel;
57 import freemarker.template.Configuration;
58 import freemarker.template.ObjectWrapper;
59 import freemarker.template.Template;
60 import freemarker.template.TemplateException;
61
62
63
64
65
66
67 public class LifecycleRenderingContext {
68
69
70
71
72 private final Environment environment;
73
74
75
76
77 private final Set<String> importedTemplates;
78
79
80
81
82 private final ByteArrayOutputStream buffer;
83
84
85
86
87 private final PrintWriter writer;
88
89
90
91
92
93
94
95 public LifecycleRenderingContext(Object model, HttpServletRequest request) {
96 try {
97 ProcessLogger.countBegin("render");
98 Map<String, Object> modelAttrs = new HashMap<String, Object>();
99 modelAttrs.put(UifConstants.DEFAULT_MODEL_NAME, model);
100 modelAttrs.put(KRADConstants.USER_SESSION_KEY, GlobalVariables.getUserSession());
101
102 request.setAttribute(UifConstants.DEFAULT_MODEL_NAME, model);
103 request.setAttribute(KRADConstants.USER_SESSION_KEY, GlobalVariables.getUserSession());
104 modelAttrs.put(UifParameters.REQUEST, request);
105
106 Map<String, String> properties = CoreApiServiceLocator.getKualiConfigurationService().getAllProperties();
107 modelAttrs.put(UifParameters.CONFIG_PROPERTIES, properties);
108
109 modelAttrs.put(UifParameters.RENDER_HELPER_METHODS, new UifRenderHelperMethods());
110
111 ByteArrayOutputStream out = new ByteArrayOutputStream();
112 writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
113
114 Configuration config = FreeMarkerInlineRenderBootstrap.getFreeMarkerConfig();
115 Template template = new Template("", new StringReader(""), config);
116
117 ServletContext servletContext = FreeMarkerInlineRenderBootstrap.getServletContext();
118 ObjectWrapper objectWrapper = FreeMarkerInlineRenderBootstrap.getObjectWrapper();
119 ServletContextHashModel servletContextHashModel = FreeMarkerInlineRenderBootstrap
120 .getServletContextHashModel();
121 TaglibFactory taglibFactory = FreeMarkerInlineRenderBootstrap.getTaglibFactory();
122
123 Response response = new Response(new MockHttpServletResponse());
124 AllHttpScopesHashModel global =
125 new AllHttpScopesHashModel(objectWrapper, servletContext, request);
126 global.put(FreemarkerServlet.KEY_JSP_TAGLIBS, taglibFactory);
127 global.put(FreemarkerServlet.KEY_APPLICATION, servletContextHashModel);
128 global.put(FreemarkerServlet.KEY_SESSION,
129 new HttpSessionHashModel(request.getSession(), objectWrapper));
130 global.put(FreemarkerServlet.KEY_REQUEST,
131 new HttpRequestHashModel(request, response, objectWrapper));
132 global.put(FreemarkerServlet.KEY_REQUEST_PARAMETERS,
133 new HttpRequestParametersHashModel(request));
134 global.put(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE,
135 new RequestContext(request, response, servletContext, modelAttrs));
136
137 global.put(UifParameters.VIEW, ViewLifecycle.getView());
138
139
140
141
142
143
144 Environment env = template.createProcessingEnvironment(global, writer);
145 env.importLib("/krad/WEB-INF/ftl/lib/krad.ftl", "krad");
146 env.importLib("/krad/WEB-INF/ftl/lib/spring.ftl", "spring");
147
148 environment = env;
149 buffer = out;
150 importedTemplates = new HashSet<String>();
151
152 } catch (IOException e) {
153 throw new IllegalStateException("Failed to initialize FreeMarker for rendering", e);
154 } catch (TemplateException e) {
155 throw new IllegalStateException("Failed to initialize FreeMarker for rendering", e);
156 } finally {
157 ProcessLogger.countEnd("render", model.getClass().getName());
158 }
159 }
160
161
162
163
164
165
166
167
168 public Environment getEnvironment() {
169 return environment;
170 }
171
172
173
174
175
176 public void clearRenderingBuffer() {
177 buffer.reset();
178 }
179
180
181
182
183 public String getRenderedOutput() {
184 try {
185 writer.flush();
186 buffer.flush();
187 return buffer.toString("UTF-8");
188 } catch (UnsupportedEncodingException e) {
189 throw new IllegalStateException("UTF-8 is unsupported", e);
190 } catch (IOException e) {
191 throw new IllegalStateException("Unexpected exception flusing buffer", e);
192 }
193 }
194
195
196
197
198
199
200 public void importTemplate(String template) {
201 if (isImported(template)) {
202 return;
203 }
204
205 try {
206 String templateNameString = TemplateCache.getFullTemplatePath(environment, "", template);
207 environment.include(environment.getTemplateForInclusion(templateNameString, null, true));
208 } catch (ParseException e) {
209 throw new IllegalStateException("Error parsing imported template " + template, e);
210 } catch (TemplateException e) {
211 throw new IllegalStateException("Error importing template " + template, e);
212 } catch (IOException e) {
213 throw new IllegalStateException("Error importing template " + template, e);
214 }
215 }
216
217 public boolean isImported(String template) {
218 return template == null || !importedTemplates.add(template);
219 }
220
221
222
223
224
225
226
227 private class Response extends HttpServletResponseWrapper {
228
229
230
231
232
233
234 public Response(HttpServletResponse response) {
235 super(response);
236 }
237
238
239
240
241 @Override
242 public ServletOutputStream getOutputStream() throws IOException {
243 return new ServletOutputStream() {
244 @Override
245 public void write(int b) throws IOException {
246 buffer.write(b);
247 }
248 };
249 }
250
251
252
253
254 @Override
255 public PrintWriter getWriter() throws IOException {
256 return writer;
257 }
258
259
260
261
262 @Override
263 public int getBufferSize() {
264 return buffer.size();
265 }
266
267
268
269
270 @Override
271 public void flushBuffer() throws IOException {
272 writer.flush();
273 }
274
275
276
277
278 @Override
279 public void reset() {
280 throw new UnsupportedOperationException("reset() should not be used during rendering");
281 }
282
283
284
285
286 @Override
287 public void resetBuffer() {
288 writer.flush();
289 buffer.reset();
290 }
291
292 }
293 }