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.module.templating;
35
36 import java.io.Writer;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.Map;
40
41 import org.apache.commons.lang.exception.ExceptionUtils;
42
43 import info.magnolia.cms.core.Content;
44 import info.magnolia.cms.core.AggregationState;
45 import info.magnolia.cms.i18n.I18nContentWrapper;
46 import info.magnolia.context.MgnlContext;
47
48
49
50
51
52
53
54
55
56
57 public abstract class AbstractRenderer implements RenderingModelBasedRenderer {
58
59 private static final String MODEL_ATTRIBUTE = RenderingModel.class.getName();
60
61 public AbstractRenderer() {
62 }
63
64 protected void render(Content content, RenderableDefinition definition, Writer out) throws RenderException {
65
66 final RenderingModel parentModel = (RenderingModel) MgnlContext.getAttribute(MODEL_ATTRIBUTE);
67
68 RenderingModel model;
69 String actionResult;
70
71 model = (RenderingModel) MgnlContext.getAttribute(ModelExecutionFilter.MODEL_ATTRIBUTE_PREFIX + content.getUUID());
72
73 if (model == null) {
74
75 model = newModel(content, definition, parentModel);
76
77 actionResult = model.execute();
78
79 if (RenderingModel.SKIP_RENDERING.equals(actionResult)) {
80 return;
81 }
82 } else {
83 actionResult = (String) MgnlContext.getAttribute(ModelExecutionFilter.ACTION_RESULT_ATTRIBUTE_PREFIX + content.getUUID());
84 if (model instanceof EarlyExecutionAware)
85 ((EarlyExecutionAware)model).setParent(parentModel);
86 }
87
88 String templatePath = determineTemplatePath(content, definition, model, actionResult);
89
90 final Map ctx = newContext();
91 final Map savedContextState = saveContextState(ctx);
92 setupContext(ctx, content, definition, model, actionResult);
93 MgnlContext.setAttribute(MODEL_ATTRIBUTE, model);
94 onRender(content, definition, out, ctx, templatePath);
95 MgnlContext.setAttribute(MODEL_ATTRIBUTE, parentModel);
96
97 restoreContext(ctx, savedContextState);
98 }
99
100 protected String determineTemplatePath(Content content, RenderableDefinition definition, RenderingModel model, final String actionResult) {
101 String templatePath = definition.determineTemplatePath(actionResult, model);
102
103 if (templatePath == null) {
104 throw new IllegalStateException("Unable to render " + definition.getClass().getName() + " " + definition.getName() + " in page " + content.getHandle() + ": templatePath not set.");
105 }
106 return templatePath;
107 }
108
109
110
111
112 public RenderingModel newModel(Content content, RenderableDefinition definition, RenderingModel parentModel) throws RenderException {
113 try {
114 final Content wrappedContent = wrapNodeForModel(content, getMainContentSafely(content));
115 return definition.newModel(wrappedContent, definition, parentModel);
116 } catch (Exception e) {
117 throw new RenderException("Can't create rendering model: " + ExceptionUtils.getRootCauseMessage(e), e);
118 }
119 }
120
121 protected Map saveContextState(final Map ctx) {
122 Map state = new HashMap();
123
124 saveAttribute(ctx, state, "content");
125 saveAttribute(ctx, state, "def");
126 saveAttribute(ctx, state, "state");
127 saveAttribute(ctx, state, "mgnl");
128 saveAttribute(ctx, state, "model");
129 saveAttribute(ctx, state, "actionResult");
130
131 saveAttribute(ctx, state, getPageAttributeName());
132 return state;
133 }
134
135 protected void saveAttribute(final Map ctx, Map state, String name) {
136 state.put(name, ctx.get(name));
137 }
138
139 protected void restoreContext(final Map ctx, Map state) {
140 for (Iterator iterator = state.keySet().iterator(); iterator.hasNext();) {
141 String name = (String) iterator.next();
142 setContextAttribute(ctx, name, state.get(name));
143 }
144 }
145
146 protected void setupContext(final Map ctx, Content content, RenderableDefinition definition, RenderingModel model, Object actionResult){
147 final Content mainContent = getMainContentSafely(content);
148
149 setContextAttribute(ctx, getPageAttributeName(), wrapNodeForTemplate(mainContent, mainContent));
150 setContextAttribute(ctx, "content", wrapNodeForTemplate(content, mainContent));
151 setContextAttribute(ctx, "def", definition);
152 setContextAttribute(ctx, "state", getAggregationStateSafely());
153 setContextAttribute(ctx, "mgnl", getMagnoliaTemplatingUtilities());
154 setContextAttribute(ctx, "model", model);
155 setContextAttribute(ctx, "actionResult", actionResult);
156 }
157
158
159
160
161 protected Content getMainContentSafely(Content current) {
162 AggregationState state = getAggregationStateSafely();
163 if(state != null){
164 return state.getMainContent();
165 }
166 return current;
167 }
168
169
170
171
172 protected AggregationState getAggrigationStateSafely() {
173 return getAggregationStateSafely();
174 }
175
176
177
178
179 protected AggregationState getAggregationStateSafely() {
180 if(MgnlContext.isWebContext()){
181 return MgnlContext.getAggregationState();
182 }
183 return null;
184 }
185
186 protected MagnoliaTemplatingUtilities getMagnoliaTemplatingUtilities() {
187 return MagnoliaTemplatingUtilities.getInstance();
188 }
189
190
191
192
193
194
195 protected Content wrapNodeForModel(Content currentContent, Content mainContent) {
196 return new I18nContentWrapper(currentContent);
197 }
198
199
200
201
202
203
204
205
206 protected Content wrapNodeForTemplate(Content currentContent, Content mainContent) {
207 return new I18nContentWrapper(currentContent);
208 }
209
210 protected Object setContextAttribute(final Map ctx, final String name, Object value) {
211 return ctx.put(name, value);
212 }
213
214
215
216
217 protected String getPageAttributeName() {
218 return "page";
219 }
220
221
222
223
224 protected abstract Map newContext();
225
226
227
228
229
230 protected abstract void onRender(Content content, RenderableDefinition definition, Writer out, Map ctx, String templatePath) throws RenderException;
231
232 }