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