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 }
85
86 String templatePath = determineTemplatePath(content, definition, model, actionResult);
87
88 final Map ctx = newContext();
89 final Map savedContextState = saveContextState(ctx);
90 setupContext(ctx, content, definition, model, actionResult);
91 MgnlContext.setAttribute(MODEL_ATTRIBUTE, model);
92 onRender(content, definition, out, ctx, templatePath);
93 MgnlContext.setAttribute(MODEL_ATTRIBUTE, parentModel);
94
95 restoreContext(ctx, savedContextState);
96 }
97
98 protected String determineTemplatePath(Content content, RenderableDefinition definition, RenderingModel model, final String actionResult) {
99 String templatePath = definition.determineTemplatePath(actionResult, model);
100
101 if (templatePath == null) {
102 throw new IllegalStateException("Unable to render " + definition.getClass().getName() + " " + definition.getName() + " in page " + content.getHandle() + ": templatePath not set.");
103 }
104 return templatePath;
105 }
106
107
108
109
110 public RenderingModel newModel(Content content, RenderableDefinition definition, RenderingModel parentModel) throws RenderException {
111 try {
112 final Content wrappedContent = wrapNodeForModel(content, getMainContentSafely(content));
113 return definition.newModel(wrappedContent, definition, parentModel);
114 } catch (Exception e) {
115 throw new RenderException("Can't create rendering model: " + ExceptionUtils.getRootCauseMessage(e), e);
116 }
117 }
118
119 protected Map saveContextState(final Map ctx) {
120 Map state = new HashMap();
121
122 saveAttribute(ctx, state, "content");
123 saveAttribute(ctx, state, "def");
124 saveAttribute(ctx, state, "state");
125 saveAttribute(ctx, state, "mgnl");
126 saveAttribute(ctx, state, "model");
127 saveAttribute(ctx, state, "actionResult");
128
129 saveAttribute(ctx, state, getPageAttributeName());
130 return state;
131 }
132
133 protected void saveAttribute(final Map ctx, Map state, String name) {
134 state.put(name, ctx.get(name));
135 }
136
137 protected void restoreContext(final Map ctx, Map state) {
138 for (Iterator iterator = state.keySet().iterator(); iterator.hasNext();) {
139 String name = (String) iterator.next();
140 setContextAttribute(ctx, name, state.get(name));
141 }
142 }
143
144 protected void setupContext(final Map ctx, Content content, RenderableDefinition definition, RenderingModel model, Object actionResult){
145 final Content mainContent = getMainContentSafely(content);
146
147 setContextAttribute(ctx, getPageAttributeName(), wrapNodeForTemplate(mainContent, mainContent));
148 setContextAttribute(ctx, "content", wrapNodeForTemplate(content, mainContent));
149 setContextAttribute(ctx, "def", definition);
150 setContextAttribute(ctx, "state", getAggregationStateSafely());
151 setContextAttribute(ctx, "mgnl", getMagnoliaTemplatingUtilities());
152 setContextAttribute(ctx, "model", model);
153 setContextAttribute(ctx, "actionResult", actionResult);
154 }
155
156
157
158
159 protected Content getMainContentSafely(Content current) {
160 AggregationState state = getAggregationStateSafely();
161 if(state != null){
162 return state.getMainContent();
163 }
164 return current;
165 }
166
167
168
169
170 protected AggregationState getAggrigationStateSafely() {
171 return getAggregationStateSafely();
172 }
173
174
175
176
177 protected AggregationState getAggregationStateSafely() {
178 if(MgnlContext.isWebContext()){
179 return MgnlContext.getAggregationState();
180 }
181 return null;
182 }
183
184 protected MagnoliaTemplatingUtilities getMagnoliaTemplatingUtilities() {
185 return MagnoliaTemplatingUtilities.getInstance();
186 }
187
188
189
190
191
192
193 protected Content wrapNodeForModel(Content currentContent, Content mainContent) {
194 return new I18nContentWrapper(currentContent);
195 }
196
197
198
199
200
201
202
203
204 protected Content wrapNodeForTemplate(Content currentContent, Content mainContent) {
205 return new I18nContentWrapper(currentContent);
206 }
207
208 protected Object setContextAttribute(final Map ctx, final String name, Object value) {
209 return ctx.put(name, value);
210 }
211
212
213
214
215 protected String getPageAttributeName() {
216 return "page";
217 }
218
219
220
221
222 protected abstract Map newContext();
223
224
225
226
227
228 protected abstract void onRender(Content content, RenderableDefinition definition, Writer out, Map ctx, String templatePath) throws RenderException;
229
230 }