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.rendering.context;
35
36 import info.magnolia.cms.core.AggregationState;
37 import info.magnolia.objectfactory.annotation.LocalScoped;
38 import info.magnolia.rendering.engine.OutputProvider;
39 import info.magnolia.rendering.engine.RenderException;
40 import info.magnolia.rendering.engine.RenderExceptionHandler;
41 import info.magnolia.rendering.template.AreaDefinition;
42 import info.magnolia.rendering.template.RenderableDefinition;
43 import info.magnolia.rendering.util.AppendableWriter;
44
45 import java.io.IOException;
46 import java.io.OutputStream;
47 import java.util.ArrayList;
48 import java.util.EmptyStackException;
49 import java.util.Enumeration;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.ListIterator;
53 import java.util.Map;
54 import java.util.Stack;
55
56 import javax.inject.Inject;
57 import javax.inject.Provider;
58 import javax.jcr.Node;
59
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63
64
65
66 @LocalScoped
67 public class AggregationStateBasedRenderingContext implements RenderingContext {
68
69
70
71 private final Logger log = LoggerFactory.getLogger(getClass());
72
73 private static class StackState {
74
75 RenderableDefinition renderableDefinition;
76 OutputProvider outputProvider;
77 Node legacyContent;
78
79 private StackState(RenderableDefinition renderableDefinition, OutputProvider outputProvider, Node legacyContent) {
80 this.renderableDefinition = renderableDefinition;
81 this.outputProvider = outputProvider;
82 this.legacyContent = legacyContent;
83 }
84 }
85
86 private final AggregationState aggregationState;
87 private final Stack<StackState> stack = new Stack<StackState>();
88 private RenderableDefinition currentRenderableDefinition;
89 private OutputProvider currentOutputProvider;
90 private final RenderExceptionHandler exceptionHandler;
91 private List<RenderingListener> listeners = new ArrayList<RenderingListener>();
92
93
94
95
96
97
98 private int depth = 0;
99
100 @Inject
101 public AggregationStateBasedRenderingContext(Provider<AggregationState> aggregationStateProvider, RenderExceptionHandler exceptionHandler) {
102 this(aggregationStateProvider.get(), exceptionHandler);
103 }
104
105 public AggregationStateBasedRenderingContext(AggregationState aggregationState, RenderExceptionHandler exceptionHandler) {
106 this.aggregationState = aggregationState;
107 this.exceptionHandler = exceptionHandler;
108 }
109
110 @Override
111 public Node getMainContent() {
112
113 return aggregationState.getMainContentNode();
114 }
115
116 @Override
117 public Node getCurrentContent() {
118 return aggregationState.getCurrentContentNode();
119 }
120
121 @Override
122 public RenderableDefinition getRenderableDefinition() {
123 return currentRenderableDefinition;
124 }
125
126 @Override
127 public AreaDefinition getParentAreaDefinition() {
128 if (currentRenderableDefinition instanceof AreaDefinition) {
129 return (AreaDefinition) currentRenderableDefinition;
130 }
131
132 Enumeration<StackState> elements = stack.elements();
133 while (elements.hasMoreElements()) {
134 StackState state = elements.nextElement();
135 if (state.renderableDefinition instanceof AreaDefinition) {
136 return (AreaDefinition) state.renderableDefinition;
137 }
138 }
139 return null;
140 }
141
142 @Override
143 public void push(Node content, RenderableDefinition renderableDefinition) {
144 push(content, renderableDefinition, null);
145 }
146
147 @Override
148 public void push(Node content, RenderableDefinition renderableDefinition, OutputProvider outputProvider) {
149
150
151
152 Node legacyContent = content;
153
154 if (aggregationState.getMainContentNode() == null) {
155 aggregationState.setMainContentNode(content);
156 }
157
158 if (depth > 0) {
159 stack.push(new StackState(currentRenderableDefinition, currentOutputProvider, aggregationState.getCurrentContentNode()));
160 }
161 aggregationState.setCurrentContentNode(content);
162 currentRenderableDefinition = renderableDefinition;
163 currentOutputProvider = outputProvider != null ? outputProvider : currentOutputProvider;
164 depth++;
165 }
166
167 @Override
168 public void pop() {
169 if (depth == 0) {
170 throw new EmptyStackException();
171 } else if (depth == 1) {
172 aggregationState.setCurrentContentNode(null);
173 currentRenderableDefinition = null;
174 currentOutputProvider = null;
175 } else {
176 StackState state = stack.pop();
177 aggregationState.setCurrentContentNode(state.legacyContent);
178 currentRenderableDefinition = state.renderableDefinition;
179 currentOutputProvider = state.outputProvider;
180 }
181 depth--;
182
183 }
184
185 @Override
186 public OutputProvider getOutputProvider() {
187 return currentOutputProvider;
188 }
189
190 @Override
191 public AppendableWriter getAppendable() throws IOException {
192 return new AppendableWriter(this.currentOutputProvider.getAppendable());
193 }
194
195 @Override
196 public OutputStream getOutputStream() throws IOException {
197 return this.currentOutputProvider.getOutputStream();
198 }
199
200 @Override
201 public void handleException(RenderException renderException) {
202 exceptionHandler.handleException(renderException, this);
203 }
204
205 @Override
206 public void setListeners(List<RenderingListener> listeners) {
207 this.listeners = listeners;
208 }
209
210 @Override
211 public void addListener(RenderingListener renderingListener) {
212 this.listeners.add(renderingListener);
213 }
214
215
216 @Override
217 public void before(Node content, RenderableDefinition definition, Map<String, Object> contextObjects, OutputProvider out) {
218 Iterator<RenderingListener> iterator = this.listeners.iterator();
219 while (iterator.hasNext()) {
220 RenderingListener listener = iterator.next();
221 try {
222 listener.before(content, definition, contextObjects, out);
223 } catch (Exception e) {
224 log.error("{}.before() failed with exception ", listener, e);
225 }
226 }
227 }
228
229
230 @Override
231 public void after(Node content, RenderableDefinition definition, Map<String, Object> contextObjects, OutputProvider out) {
232 ListIterator<RenderingListener> iterator = this.listeners.listIterator(listeners.size());
233 while (iterator.hasPrevious()) {
234 RenderingListener listener = iterator.previous();
235 try {
236 listener.after(content, definition, contextObjects, out);
237 } catch (Exception e) {
238 log.error("{}.before() failed with exception ", listener, e);
239 }
240 }
241 }
242 }