KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > filters > MgnlCmsFilter


1 /**
2  *
3  * Magnolia and its source-code is licensed under the LGPL.
4  * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
5  * When copying, adapting, or redistributing this document in keeping with the guidelines above,
6  * you are required to provide proper attribution to obinary.
7  * If you reproduce or distribute the document without making any substantive modifications to its content,
8  * please use the following attribution line:
9  *
10  * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved.
11  *
12  */

13 package info.magnolia.cms.filters;
14
15 import info.magnolia.cms.beans.config.ConfigLoader;
16 import info.magnolia.cms.beans.config.Template;
17 import info.magnolia.cms.beans.config.TemplateManager;
18 import info.magnolia.cms.beans.config.TemplateRendererManager;
19 import info.magnolia.cms.beans.config.URI2RepositoryManager;
20 import info.magnolia.cms.beans.config.URI2RepositoryMapping;
21 import info.magnolia.cms.beans.runtime.File;
22 import info.magnolia.cms.beans.runtime.TemplateRenderer;
23 import info.magnolia.cms.core.*;
24 import info.magnolia.cms.security.AccessDeniedException;
25 import info.magnolia.cms.security.Permission;
26 import info.magnolia.cms.security.AccessManager;
27 import info.magnolia.context.MgnlContext;
28
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31
32 import javax.jcr.PathNotFoundException;
33 import javax.jcr.PropertyType;
34 import javax.jcr.RepositoryException;
35 import javax.jcr.Value;
36 import javax.servlet.Filter JavaDoc;
37 import javax.servlet.FilterChain JavaDoc;
38 import javax.servlet.FilterConfig JavaDoc;
39 import javax.servlet.ServletException JavaDoc;
40 import javax.servlet.ServletOutputStream JavaDoc;
41 import javax.servlet.ServletRequest JavaDoc;
42 import javax.servlet.ServletResponse JavaDoc;
43 import javax.servlet.http.HttpServletRequest JavaDoc;
44 import javax.servlet.http.HttpServletResponse JavaDoc;
45
46 import org.apache.commons.io.IOUtils;
47 import org.apache.commons.lang.StringUtils;
48 import org.apache.commons.lang.exception.NestableRuntimeException;
49 import org.apache.commons.lang.math.NumberUtils;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53
54 /**
55  * CMS filter responsible for content aggregation and dispatching
56  * @author Philipp Bracher
57  * @version $Revision: 7685 $ ($Author: scharles $)
58  */

59 public class MgnlCmsFilter implements Filter JavaDoc {
60
61     private static final String JavaDoc BYPASS_PARAM = "bypass";
62
63     private static Logger log = LoggerFactory.getLogger(MgnlCmsFilter.class);
64
65     private String JavaDoc[] bypass;
66
67     private static final String JavaDoc NODE_DATA_TEMPLATE = "nodeDataTemplate";
68
69     private static final String JavaDoc VERSION_NUMBER = "mgnlVersion"; //$NON-NLS-1$
70

71
72     /**
73      * @see javax.servlet.Filter#destroy()
74      */

75     public void destroy() {
76         // unused
77
}
78
79     /**
80      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
81      */

82     public void init(FilterConfig JavaDoc filterConfig) throws ServletException JavaDoc {
83         this.bypass = StringUtils.split(filterConfig.getInitParameter(BYPASS_PARAM), ", ");
84         if (this.bypass == null) {
85             this.bypass = new String JavaDoc[0];
86         }
87     }
88
89     public void doFilter(ServletRequest JavaDoc req, ServletResponse JavaDoc resp, FilterChain JavaDoc chain) throws IOException JavaDoc,
90         ServletException JavaDoc {
91
92         HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) req;
93         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) resp;
94
95         String JavaDoc requestURI = Path.getURI(request);
96         String JavaDoc pathInfo = request.getPathInfo();
97
98         if (pathInfo == null && !startsWithAny(bypass, requestURI)) {
99             handle(request, response);
100         } else {
101             // only continue if bypassed by this filter, independent of return status from handle(request, response)
102
// since it will return false on exceptions like AccessDenied in which case it should not continue
103
chain.doFilter(request, response);
104         }
105     }
106
107     /**
108      * All HTTP/s requests are handled here.
109      * @param request HttpServletRequest
110      * @param response HttpServletResponse
111      * @throws IOException can be thrown when the servlet is unable to write to the response stream
112      * @throws ServletException
113      */

114     public boolean handle(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws IOException JavaDoc,
115         ServletException JavaDoc {
116
117         if (ConfigLoader.isBootstrapping()) {
118             // @todo a nice page, with the log content...
119
response.getWriter().write("Magnolia bootstrapping has failed, check bootstrap.log in magnolia/logs"); //$NON-NLS-1$
120
return false;
121         }
122
123         setHandleAndMapping(request);
124
125         try {
126             authorize(request);
127             // aggregate content
128
boolean success = collect(request);
129
130             if (success) {
131
132                 Template template = (Template) request.getAttribute(Aggregator.TEMPLATE);
133
134                 if (template != null) {
135                     try {
136                         String JavaDoc type = template.getType();
137                         TemplateRenderer renderer = TemplateRendererManager.getInstance().getRenderer(type);
138
139                         if (renderer == null) {
140                             throw new RuntimeException JavaDoc("No renderer found for type " + type);
141                         }
142                         renderer.renderTemplate(template, request, response);
143                     }
144                     catch (IOException JavaDoc e) {
145                         log.error(e.getMessage(), e);
146                         throw e;
147                     }
148                     catch (ServletException JavaDoc e) {
149                         log.error(e.getMessage(), e);
150                         throw e;
151                     }
152                     catch (Exception JavaDoc e) {
153                         // @todo better handling of rendering exception
154
log.error(e.getMessage(), e);
155                         if (!response.isCommitted()) {
156                             response.reset();
157                             response.setContentType("text/html");
158                         }
159                         throw new NestableRuntimeException(e);
160                     }
161                 }
162                 else {
163                     // direct request
164
handleResourceRequest(request, response);
165                 }
166
167             }
168             else {
169                 if (log.isDebugEnabled()) {
170                     log.debug(
171                         "Resource not found, redirecting request for [{}] to 404 URI", request.getRequestURI()); //$NON-NLS-1$
172
}
173
174                 if (!response.isCommitted()) {
175                     response.sendError(HttpServletResponse.SC_NOT_FOUND);
176                 }
177                 else {
178                     log.info("Unable to redirect to 404 page, response is already committed. URI was {}", //$NON-NLS-1$
179
request.getRequestURI());
180                 }
181                 return false;
182             }
183         }
184         catch (AccessDeniedException e) {
185             // don't throw further, simply return error and break filter chain
186
log.debug(e.getMessage());
187             if (!response.isCommitted())
188                 response.sendError(HttpServletResponse.SC_FORBIDDEN);
189             return false;
190         }
191         catch (RepositoryException e) {
192             log.error(e.getMessage(), e);
193             throw new ServletException JavaDoc(e.getMessage(), e);
194         }
195
196         return true;
197     }
198
199     /**
200      * Sets the proper handle, selector and extension into the request variables
201      * @param request
202      */

203     protected void setHandleAndMapping(HttpServletRequest JavaDoc request) {
204         String JavaDoc uri = Path.getURI(request);
205         int firstDotPos = StringUtils.indexOf(uri, '.', StringUtils.lastIndexOf(uri, '/'));
206         String JavaDoc handle;
207         String JavaDoc selector;
208         String JavaDoc extension;
209         if (firstDotPos > -1) {
210             int lastDotPos = StringUtils.lastIndexOf(uri, '.');
211             handle = StringUtils.substring(uri, 0, firstDotPos);
212             selector = StringUtils.substring(uri, firstDotPos + 1, lastDotPos);
213             extension = StringUtils.substring(uri, lastDotPos + 1);
214         }
215         else {
216             // no dots (and no extension)
217
handle = uri;
218             selector = "";
219             extension = "";
220         }
221
222         URI2RepositoryMapping mapping = URI2RepositoryManager.getInstance().getMapping(uri);
223
224         // remove prefix if any
225
handle = mapping.getHandle(handle);
226
227         request.setAttribute(Aggregator.REPOSITORY, mapping.getRepository());
228         request.setAttribute(Aggregator.MAPPING, mapping);
229         request.setAttribute(Aggregator.HANDLE, handle);
230         request.setAttribute(Aggregator.SELECTOR, selector);
231         request.setAttribute(Aggregator.EXTENSION, extension);
232     }
233
234     /**
235      * Uses access manager to authorize this request.
236      * @param request HttpServletRequest as received by the service method
237      * @throws AccessDeniedException if the given request is not authorized
238      */

239     protected void authorize(HttpServletRequest JavaDoc request) throws AccessDeniedException {
240         AccessManager accessManager = MgnlContext.getAccessManager(getRepository(request));
241         if (null != accessManager) {
242             Access.isGranted(accessManager, Path.getHandle(request), Permission.READ);
243         }
244     }
245
246     /**
247      * Return the repository used for this request. This uses a url to repository mapping.
248      * @return repository name
249      */

250     protected String JavaDoc getRepository(HttpServletRequest JavaDoc req) {
251         return (String JavaDoc) req.getAttribute(Aggregator.REPOSITORY);
252     }
253
254     /**
255      * Get the requested resource and copy it to the ServletOutputStream, bit by bit.
256      * @param request HttpServletRequest as given by the servlet container
257      * @param response HttpServletResponse as given by the servlet container
258      * @throws IOException standard servlet exception
259      */

260     protected void handleResourceRequest(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws IOException JavaDoc {
261
262         String JavaDoc resourceHandle = (String JavaDoc) request.getAttribute(Aggregator.HANDLE);
263
264         log.debug("handleResourceRequest, resourceHandle=\"{}\"", resourceHandle); //$NON-NLS-1$
265

266         if (StringUtils.isNotEmpty(resourceHandle)) {
267
268             HierarchyManager hm = MgnlContext.getHierarchyManager(getRepository(request));
269
270             InputStream JavaDoc is = null;
271             try {
272                 is = getNodedataAstream(resourceHandle, hm, response);
273                 if (null != is) {
274                     // todo find better way to discover if resource could be compressed, implement as in "cache"
275
// browsers will always send header saying either it can decompress or not, but
276
// resources like jpeg which is already compressed should be not be written on
277
// zipped stream otherwise some browsers takes a long time to render
278
sendUnCompressed(is, response);
279                     IOUtils.closeQuietly(is);
280                     return;
281                 }
282             }
283             catch (IOException JavaDoc e) {
284                 // don't log at error level since tomcat tipically throws a
285
// org.apache.catalina.connector.ClientAbortException if the user stops loading the page
286
if (log.isDebugEnabled()) {
287                     log.debug(
288                         "Exception while dispatching resource " + e.getClass().getName() + ": " + e.getMessage(), e); //$NON-NLS-1$ //$NON-NLS-2$
289
}
290             }
291             catch (Exception JavaDoc e) {
292                 log.error("Exception while dispatching resource " + e.getClass().getName() + ": " + e.getMessage(), e); //$NON-NLS-1$ //$NON-NLS-2$
293
}
294             finally {
295                 IOUtils.closeQuietly(is);
296             }
297         }
298         if (log.isDebugEnabled()) {
299             log.debug("Resource not found, redirecting request for [{}] to 404 URI", request.getRequestURI()); //$NON-NLS-1$
300
}
301
302         if (!response.isCommitted()) {
303             response.sendError(HttpServletResponse.SC_NOT_FOUND);
304         }
305         else {
306             log.info("Unable to redirect to 404 page, response is already committed"); //$NON-NLS-1$
307
}
308
309     }
310
311     /**
312      * Send data as is.
313      * @param is Input stream for the resource
314      * @param response HttpServletResponse as received by the service method
315      * @throws IOException standard servlet exception
316      */

317     private void sendUnCompressed(InputStream JavaDoc is, HttpServletResponse JavaDoc response) throws IOException JavaDoc {
318         ServletOutputStream JavaDoc os = response.getOutputStream();
319         byte[] buffer = new byte[8192];
320         int read;
321         while ((read = is.read(buffer)) > 0) {
322             os.write(buffer, 0, read);
323         }
324         os.flush();
325         IOUtils.closeQuietly(os);
326     }
327
328     /**
329      * @param path path for nodedata in jcr repository
330      * @param hm Hierarchy manager
331      * @param res HttpServletResponse
332      * @return InputStream or <code>null</code> if nodeData is not found
333      */

334     private InputStream JavaDoc getNodedataAstream(String JavaDoc path, HierarchyManager hm, HttpServletResponse JavaDoc res) {
335
336         log.debug("getNodedataAstream for path \"{}\"", path); //$NON-NLS-1$
337

338         try {
339             NodeData atom = hm.getNodeData(path);
340             if (atom != null) {
341                 if (atom.getType() == PropertyType.BINARY) {
342
343                     String JavaDoc sizeString = atom.getAttribute("size"); //$NON-NLS-1$
344
if (NumberUtils.isNumber(sizeString)) {
345                         res.setContentLength(Integer.parseInt(sizeString));
346                     }
347                 }
348
349                 Value value = atom.getValue();
350                 if (value != null) {
351                     return value.getStream();
352                 }
353             }
354
355             log.warn("Resource not found: [{}]", path); //$NON-NLS-1$
356

357         }
358         catch (PathNotFoundException e) {
359             log.warn("Resource not found: [{}]", path); //$NON-NLS-1$
360
}
361         catch (RepositoryException e) {
362             log.error("RepositoryException while reading Resource [" + path + "]", e); //$NON-NLS-1$ //$NON-NLS-2$
363
}
364         return null;
365     }
366
367     /**
368      * Collect content from the pre configured repository and attach it to the HttpServletRequest.
369      * @throws PathNotFoundException
370      * @throws RepositoryException
371      */

372     protected boolean collect(HttpServletRequest JavaDoc request) throws PathNotFoundException, RepositoryException {
373         String JavaDoc handle = Path.getHandle(request);
374         String JavaDoc extension = Path.getExtension(request);
375         String JavaDoc repository = getRepository(request);
376         HierarchyManager hierarchyManager = MgnlContext.getHierarchyManager(repository);
377
378         Content requestedPage = null;
379         NodeData requestedData = null;
380         Template template = null;
381
382         if (hierarchyManager.isPage(handle)) {
383             requestedPage = hierarchyManager.getContent(handle);
384
385             // check if its a request for a versioned page
386
if (request.getParameter(VERSION_NUMBER) != null) {
387                 // get versioned state
388
try {
389                     requestedPage = requestedPage.getVersionedContent(request.getParameter(VERSION_NUMBER));
390                 }
391                 catch (RepositoryException re) {
392                     log.debug(re.getMessage(), re);
393                     log.error("Unable to get versioned state, rendering current state of {}", handle);
394                 }
395             }
396
397             String JavaDoc templateName = requestedPage.getMetaData().getTemplate();
398
399             if (StringUtils.isBlank(templateName)) {
400                 log.error("No template configured for page [{}].", requestedPage.getHandle()); //$NON-NLS-1$
401
}
402
403             template = TemplateManager.getInstance().getInfo(templateName, extension);
404
405             if (template == null) {
406                 log.error("Template [{}] for page [{}] not found.", //$NON-NLS-1$
407
templateName,
408                     requestedPage.getHandle());
409             }
410         }
411         else {
412             if (hierarchyManager.isNodeData(handle)) {
413                 requestedData = hierarchyManager.getNodeData(handle);
414             }
415             else {
416                 // check again, resource might have different name
417
int lastIndexOfSlash = handle.lastIndexOf("/"); //$NON-NLS-1$
418

419                 if (lastIndexOfSlash > 0) {
420
421                     handle = StringUtils.substringBeforeLast(handle, "/"); //$NON-NLS-1$
422

423                     try {
424                         requestedData = hierarchyManager.getNodeData(handle);
425                         // set the new handle pointing to the real node
426
request.setAttribute(Aggregator.HANDLE, handle);
427
428                         // this is needed for binary nodedata, e.g. images are found using the path:
429
// /features/integration/headerImage instead of /features/integration/headerImage/header30_2
430

431                     }
432                     catch (PathNotFoundException e) {
433                         // no page available
434
return false;
435                     }
436                     catch (RepositoryException e) {
437                         log.debug(e.getMessage(), e);
438                         return false;
439                     }
440                 }
441             }
442
443             if (requestedData != null) {
444                 String JavaDoc templateName = requestedData.getAttribute(NODE_DATA_TEMPLATE);
445
446                 if (!StringUtils.isEmpty(templateName)) {
447                     template = TemplateManager.getInstance().getInfo(templateName, extension);
448                 }
449             }
450             else {
451                 return false;
452             }
453         }
454
455         // Attach all collected information to the HttpServletRequest.
456
if (requestedPage != null) {
457             request.setAttribute(Aggregator.ACTPAGE, requestedPage);
458             request.setAttribute(Aggregator.CURRENT_ACTPAGE, requestedPage);
459         }
460         if ((requestedData != null) && (requestedData.getType() == PropertyType.BINARY)) {
461             File file = new File();
462             file.setProperties(requestedData);
463             file.setNodeData(requestedData);
464             request.setAttribute(Aggregator.FILE, file);
465         }
466
467         request.setAttribute(Aggregator.TEMPLATE, template);
468
469         return true;
470     }
471
472     boolean startsWithAny(String JavaDoc[] array, String JavaDoc check) {
473         for (int j = 0; j < array.length; j++) {
474             String JavaDoc string = array[j];
475             if (check.startsWith(string)) {
476                 return true;
477             }
478         }
479         return false;
480     }
481
482 }
483
Popular Tags