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.engine;
35
36 import info.magnolia.registry.RegistrationException;
37 import info.magnolia.rendering.context.RenderingContext;
38 import info.magnolia.rendering.listeners.AbstractRenderingListener;
39 import info.magnolia.rendering.listeners.AbstractRenderingListener.RenderingListenerReturnCode;
40 import info.magnolia.rendering.renderer.Renderer;
41 import info.magnolia.rendering.renderer.registry.RendererRegistry;
42 import info.magnolia.rendering.template.RenderableDefinition;
43 import info.magnolia.rendering.template.assignment.TemplateDefinitionAssignment;
44 import info.magnolia.rendering.template.variation.RenderableVariationResolver;
45
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.Iterator;
50 import java.util.LinkedList;
51 import java.util.Map;
52
53 import javax.inject.Provider;
54 import javax.jcr.Node;
55 import javax.servlet.http.HttpServletResponse;
56
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63 public class DefaultRenderingEngine implements RenderingEngine {
64
65 protected static final Map<String, Object> EMPTY_CONTEXT = Collections.emptyMap();
66
67 private RendererRegistry rendererRegistry;
68 private TemplateDefinitionAssignment templateDefinitionAssignment;
69 private Provider<RenderingContext> renderingContextProvider;
70 private RenderableVariationResolver variationResolver;
71
72 private Boolean autoPopulateFromRequest = true;
73 private Boolean renderEmptyAreas = true;
74
75 private LinkedList<AbstractRenderingListener> listeners = new LinkedList<AbstractRenderingListener>();
76
77 private static final Logger log = LoggerFactory.getLogger(DefaultRenderingEngine.class);
78
79
80
81
82 protected DefaultRenderingEngine() {
83 }
84
85 public DefaultRenderingEngine(RendererRegistry rendererRegistry, TemplateDefinitionAssignment templateDefinitionAssignment, RenderableVariationResolver variationResolver, Provider<RenderingContext> renderingContextProvider) {
86 this.rendererRegistry = rendererRegistry;
87 this.templateDefinitionAssignment = templateDefinitionAssignment;
88 this.variationResolver = variationResolver;
89 this.renderingContextProvider = renderingContextProvider;
90 }
91
92 @Override
93 public void render(Node content, OutputProvider out) throws RenderException {
94 render(content, EMPTY_CONTEXT, out);
95 }
96
97 @Override
98 public void render(Node content, Map<String, Object> contextObjects, OutputProvider out) throws RenderException {
99 render(content, getRenderableDefinitionFor(content), contextObjects, out);
100 }
101
102 @Override
103 public void render(Node content, RenderableDefinition definition, Map<String, Object> contextObjects, OutputProvider out) throws RenderException {
104
105 RenderableDefinition variation = variationResolver.resolveVariation(definition);
106 definition = variation != null ? variation : definition;
107
108 final Renderer renderer = getRendererFor(definition);
109 final RenderingContext renderingContext = getRenderingContext();
110
111 renderingContext.push(content, definition, out);
112
113 try {
114 Collection<RenderingListenerReturnCode> listenerResults = renderingContext.before(content, definition, contextObjects, out);
115 if (listenerResults.contains(RenderingListenerReturnCode.SKIP) || listenerResults.contains(RenderingListenerReturnCode.STOP)) {
116 return;
117 }
118 renderer.render(renderingContext, contextObjects);
119 } catch (RenderException e) {
120 renderingContext.handleException(e);
121 } finally {
122 renderingContext.after(content, definition, contextObjects, out);
123 renderingContext.pop();
124 }
125 }
126
127 protected RenderableDefinition getRenderableDefinitionFor(Node content) throws RenderException {
128 try {
129 return templateDefinitionAssignment.getAssignedTemplateDefinition(content);
130 } catch (RegistrationException e) {
131 throw new RenderException("Can't resolve RenderableDefinition for node [" + content + "]", e);
132 }
133 }
134
135 protected Renderer getRendererFor(RenderableDefinition definition) throws RenderException {
136 final String renderType = definition.getRenderType();
137 if (renderType == null) {
138 throw new RenderException("No renderType defined for definition [" + definition + "]");
139 }
140 try {
141 return rendererRegistry.getRenderer(renderType);
142 } catch (RegistrationException e) {
143 throw new RenderException("Can't find renderer [" + renderType + "]", e);
144 }
145 }
146
147 @Override
148 public RenderingContext getRenderingContext() {
149 return renderingContextProvider.get();
150 }
151
152 @Override
153 public Collection<RenderingListenerReturnCode> initListeners(OutputProvider output, HttpServletResponse response) {
154 Iterator<AbstractRenderingListener> iterator = this.listeners.iterator();
155 Collection<RenderingListenerReturnCode> results = new ArrayList<RenderingListenerReturnCode>();
156 RenderingContext context = this.getRenderingContext();
157 context.setListeners(new LinkedList<AbstractRenderingListener>());
158
159 while (iterator.hasNext()) {
160 AbstractRenderingListener listener = iterator.next();
161 try {
162 AbstractRenderingListener listenerCopy = listener.copy();
163 RenderingListenerReturnCode result = listenerCopy.init(output, response);
164 if (result == RenderingListenerReturnCode.SKIP) {
165 continue;
166 }
167 context.addListener(listenerCopy);
168 if (result != null) {
169 results.add(result);
170 }
171 } catch (Exception e) {
172 log.error("Error when instantiating listener '{}'.", listener, e);
173 }
174 }
175 return results;
176 }
177
178 @Override
179 public Boolean getAutoPopulateFromRequest() {
180 return autoPopulateFromRequest;
181 }
182
183 public void setAutoPopulateFromRequest(Boolean autopopulateFromRequest) {
184 this.autoPopulateFromRequest = autopopulateFromRequest;
185 }
186
187 @Override
188 public Boolean getRenderEmptyAreas() {
189 return renderEmptyAreas;
190 }
191
192 public void setRenderEmptyAreas(Boolean renderEmptyAreas) {
193 this.renderEmptyAreas = renderEmptyAreas;
194 }
195
196 public LinkedList<AbstractRenderingListener> getListeners() {
197 return listeners;
198 }
199
200 public void setListeners(LinkedList<AbstractRenderingListener> listeners) {
201 this.listeners = listeners;
202 }
203 }