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.cms.core.AggregationState;
37 import info.magnolia.cms.core.MgnlNodeType;
38 import info.magnolia.cms.filters.AbstractMgnlFilter;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.jcr.wrapper.ChannelVisibilityContentDecorator;
41 import info.magnolia.registry.RegistrationException;
42 import info.magnolia.rendering.template.TemplateDefinition;
43 import info.magnolia.rendering.template.registry.TemplateDefinitionRegistry;
44
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.util.Collections;
48
49 import javax.jcr.Node;
50 import javax.jcr.PathNotFoundException;
51 import javax.jcr.Property;
52 import javax.jcr.RepositoryException;
53 import javax.jcr.Session;
54 import javax.servlet.FilterChain;
55 import javax.servlet.ServletException;
56 import javax.servlet.ServletOutputStream;
57 import javax.servlet.http.HttpServletRequest;
58 import javax.servlet.http.HttpServletResponse;
59
60 import org.apache.commons.io.IOUtils;
61 import org.apache.commons.lang.StringUtils;
62 import org.apache.commons.lang.math.NumberUtils;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66
67
68
69
70
71
72
73
74 public class RenderingFilter extends AbstractMgnlFilter {
75
76 private static final Logger log = LoggerFactory.getLogger(RenderingFilter.class);
77
78 private final RenderingEngine renderingEngine;
79
80 private final TemplateDefinitionRegistry templateDefinitionRegistry;
81
82 public RenderingFilter(RenderingEngine renderingEngine, TemplateDefinitionRegistry templateDefinitionRegistry) {
83 this.renderingEngine = renderingEngine;
84 this.templateDefinitionRegistry = templateDefinitionRegistry;
85 }
86
87 @Override
88 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException{
89 final AggregationState aggregationState = MgnlContext.getAggregationState();
90
91 String templateName = aggregationState.getTemplateName();
92 if (StringUtils.isNotEmpty(templateName)) {
93 try {
94
95
96 if (response != MgnlContext.getWebContext().getResponse()) {
97 log.warn("Context response not synced. This may lead to discrepancies in rendering.");
98 }
99
100 Node content = aggregationState.getMainContent().getJCRNode();
101
102
103 if (!isVisible(content, request, response, aggregationState)) {
104 if (!response.isCommitted()) {
105 response.sendError(HttpServletResponse.SC_NOT_FOUND);
106 }
107 else {
108 log.info("Unable to redirect to 404 page for {}, response is already committed", request.getRequestURI());
109 }
110 return;
111 }
112
113 render(content, templateName, response);
114
115 try {
116 response.flushBuffer();
117 }
118 catch (IOException e) {
119
120
121 log.debug("Exception flushing response " + e.getClass().getName() + ": " + e.getMessage(), e);
122 }
123
124 }
125 catch (RenderException e) {
126
127
128 log.error(e.getMessage(), e);
129 throw new ServletException(e);
130 }
131 catch (Exception e) {
132
133 log.error(e.getMessage(), e);
134 if (!response.isCommitted()) {
135 response.setContentType("text/html");
136 }
137 throw new RuntimeException(e);
138 }
139 }
140 else {
141
142 handleResourceRequest(aggregationState, request, response);
143 }
144
145
146
147
148 }
149
150 protected boolean isVisible(Node content, HttpServletRequest request, HttpServletResponse response, AggregationState aggregationState) {
151
152
153 if (aggregationState.getChannel() != null) {
154 String currentChannel = aggregationState.getChannel().getName();
155 if (StringUtils.isNotEmpty(currentChannel) && !currentChannel.equalsIgnoreCase("all")) {
156 ChannelVisibilityContentDecorator decorator = new ChannelVisibilityContentDecorator(currentChannel);
157 return decorator.evaluateNode(content);
158 }
159 }
160
161 return true;
162 }
163
164 protected void render(Node content, String templateName, HttpServletResponse response) throws RenderException {
165
166 TemplateDefinition templateDefinition;
167 try {
168 templateDefinition = templateDefinitionRegistry.getTemplateDefinition(templateName);
169 }
170 catch (RegistrationException e) {
171 throw new RenderException(e);
172 }
173 renderingEngine.render(content, templateDefinition, Collections.<String, Object> emptyMap(), new ResponseOutputProvider(response));
174 }
175
176
177
178
179
180
181
182
183 protected void handleResourceRequest(AggregationState aggregationState, HttpServletRequest request, HttpServletResponse response) throws IOException {
184
185 final String resourceHandle = aggregationState.getHandle();
186
187 log.debug("handleResourceRequest, resourceHandle=\"{}\"", resourceHandle);
188
189 if (StringUtils.isNotEmpty(resourceHandle)) {
190
191
192 InputStream is = null;
193 try {
194 Session session = MgnlContext.getJCRSession(aggregationState.getRepository());
195 is = getNodedataAsStream(resourceHandle, session, response);
196 if (null != is) {
197
198
199 sendUnCompressed(is, response);
200 IOUtils.closeQuietly(is);
201 return;
202 }
203 }
204 catch (IOException e) {
205
206
207 log.debug("Exception while dispatching resource " + e.getClass().getName() + ": " + e.getMessage(), e);
208 return;
209 }
210 catch (Exception e) {
211 log.error("Exception while dispatching resource " + e.getClass().getName() + ": " + e.getMessage(), e);
212 return;
213 }
214 finally {
215 IOUtils.closeQuietly(is);
216 }
217 }
218 log.debug("Resource not found, redirecting request for [{}] to 404 URI", request.getRequestURI());
219
220 if (!response.isCommitted()) {
221 response.sendError(HttpServletResponse.SC_NOT_FOUND);
222 }
223 else {
224 log.info("Unable to redirect to 404 page for {}, response is already committed", request.getRequestURI());
225 }
226
227 }
228
229
230
231
232
233
234
235 private void sendUnCompressed(InputStream is, HttpServletResponse response) throws IOException {
236 ServletOutputStream os = response.getOutputStream();
237 byte[] buffer = new byte[8192];
238 int read;
239 while ((read = is.read(buffer)) > 0) {
240 os.write(buffer, 0, read);
241 }
242 os.flush();
243 IOUtils.closeQuietly(os);
244 }
245
246 private InputStream getNodedataAsStream(String path, Session session, HttpServletResponse res) {
247
248 log.debug("getNodedataAstream for path \"{}\"", path);
249
250 try {
251 Node atom = session.getNode(path);
252 if (atom != null) {
253 if (atom.hasProperty(MgnlNodeType.JCR_DATA)) {
254 Property sizeProperty = atom.getProperty("size");
255 String sizeString = sizeProperty == null ? "" : sizeProperty.getString();
256 if (NumberUtils.isNumber(sizeString)) {
257 res.setContentLength(Integer.parseInt(sizeString));
258 }
259 }
260 Property streamProperty = atom.getProperty(MgnlNodeType.JCR_DATA);
261 return streamProperty.getStream();
262 }
263
264 log.warn("Resource not found: [{}]", path);
265
266 }
267 catch (PathNotFoundException e) {
268 log.warn("Resource not found: [{}]", path);
269 }
270 catch (RepositoryException e) {
271 log.error("RepositoryException while reading Resource [" + path + "]", e);
272 }
273 return null;
274 }
275
276 }