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 private Boolean escapeHtml = false;
75
76 private LinkedList<AbstractRenderingListener> listeners = new LinkedList<AbstractRenderingListener>();
77
78 private static final Logger log = LoggerFactory.getLogger(DefaultRenderingEngine.class);
79
80
81
82
83 protected DefaultRenderingEngine() {
84 }
85
86 public DefaultRenderingEngine(RendererRegistry rendererRegistry, TemplateDefinitionAssignment templateDefinitionAssignment, RenderableVariationResolver variationResolver, Provider<RenderingContext> renderingContextProvider) {
87 this.rendererRegistry = rendererRegistry;
88 this.templateDefinitionAssignment = templateDefinitionAssignment;
89 this.variationResolver = variationResolver;
90 this.renderingContextProvider = renderingContextProvider;
91 }
92
93 @Override
94 public void render(Node content, OutputProvider out) throws RenderException {
95 render(content, EMPTY_CONTEXT, out);
96 }
97
98 @Override
99 public void render(Node content, Map<String, Object> contextObjects, OutputProvider out) throws RenderException {
100 render(content, getRenderableDefinitionFor(content), contextObjects, out);
101 }
102
103 @Override
104 public void render(Node content, RenderableDefinition definition, Map<String, Object> contextObjects, OutputProvider out) throws RenderException {
105
106 RenderableDefinition variation = variationResolver.resolveVariation(definition);
107 definition = variation != null ? variation : definition;
108
109 final Renderer renderer = getRendererFor(definition);
110 final RenderingContext renderingContext = getRenderingContext();
111
112 renderingContext.push(content, definition, out);
113
114 try {
115 Collection<RenderingListenerReturnCode> listenerResults = renderingContext.before(content, definition, contextObjects, out);
116 if (listenerResults.contains(RenderingListenerReturnCode.SKIP) || listenerResults.contains(RenderingListenerReturnCode.STOP)) {
117 return;
118 }
119 renderer.render(renderingContext, contextObjects);
120 } catch (RenderException e) {
121 renderingContext.handleException(e);
122 } finally {
123 renderingContext.after(content, definition, contextObjects, out);
124 renderingContext.pop();
125 }
126 }
127
128 protected RenderableDefinition getRenderableDefinitionFor(Node content) throws RenderException {
129 try {
130 return templateDefinitionAssignment.getAssignedTemplateDefinition(content);
131 } catch (RegistrationException e) {
132 throw new RenderException("Can't resolve RenderableDefinition for node [" + content + "]", e);
133 }
134 }
135
136 protected Renderer getRendererFor(RenderableDefinition definition) throws RenderException {
137 final String renderType = definition.getRenderType();
138 if (renderType == null) {
139 throw new RenderException("No renderType defined for definition [" + definition + "]");
140 }
141 try {
142 return rendererRegistry.getRenderer(renderType);
143 } catch (RegistrationException e) {
144 throw new RenderException("Can't find renderer [" + renderType + "]", e);
145 }
146 }
147
148 @Override
149 public RenderingContext getRenderingContext() {
150 return renderingContextProvider.get();
151 }
152
153 @Override
154 public Collection<RenderingListenerReturnCode> initListeners(OutputProvider output, HttpServletResponse response) {
155 Iterator<AbstractRenderingListener> iterator = this.listeners.iterator();
156 Collection<RenderingListenerReturnCode> results = new ArrayList<RenderingListenerReturnCode>();
157 RenderingContext context = this.getRenderingContext();
158 context.setListeners(new LinkedList<AbstractRenderingListener>());
159
160 while (iterator.hasNext()) {
161 AbstractRenderingListener listener = iterator.next();
162 try {
163 AbstractRenderingListener listenerCopy = listener.copy();
164 RenderingListenerReturnCode result = listenerCopy.init(output, response);
165 if (result == RenderingListenerReturnCode.SKIP) {
166 continue;
167 }
168 context.addListener(listenerCopy);
169 if (result != null) {
170 results.add(result);
171 }
172 } catch (Exception e) {
173 log.error("Error when instantiating listener '{}'.", listener, e);
174 }
175 }
176 return results;
177 }
178
179 @Override
180 public Boolean getAutoPopulateFromRequest() {
181 return autoPopulateFromRequest;
182 }
183
184 public void setAutoPopulateFromRequest(Boolean autopopulateFromRequest) {
185 this.autoPopulateFromRequest = autopopulateFromRequest;
186 }
187
188 @Override
189 public Boolean getRenderEmptyAreas() {
190 return renderEmptyAreas;
191 }
192
193 public void setRenderEmptyAreas(Boolean renderEmptyAreas) {
194 this.renderEmptyAreas = renderEmptyAreas;
195 }
196
197 public LinkedList<AbstractRenderingListener> getListeners() {
198 return listeners;
199 }
200
201 public void setListeners(LinkedList<AbstractRenderingListener> listeners) {
202 this.listeners = listeners;
203 }
204
205 public void setEscapeHtml(Boolean escapeHtml) {
206 this.escapeHtml = escapeHtml;
207 }
208
209 @Override
210 public Boolean getEscapeHtml() {
211 return escapeHtml;
212 }
213 }