KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > flex > CmsFlexController


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/flex/CmsFlexController.java,v $
3  * Date : $Date: 2006/10/26 12:25:34 $
4  * Version: $Revision: 1.36 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.flex;
33
34 import org.opencms.file.CmsObject;
35 import org.opencms.file.CmsResource;
36 import org.opencms.main.CmsLog;
37 import org.opencms.util.CmsRequestUtil;
38
39 import java.util.List JavaDoc;
40 import java.util.Vector JavaDoc;
41
42 import javax.servlet.ServletRequest JavaDoc;
43 import javax.servlet.http.HttpServletRequest JavaDoc;
44 import javax.servlet.http.HttpServletResponse JavaDoc;
45
46 import org.apache.commons.logging.Log;
47
48 /**
49  * Controller for getting access to the CmsObject, should be used as a
50  * request attribute.<p>
51  *
52  * @author Alexander Kandzior
53  *
54  * @version $Revision: 1.36 $
55  *
56  * @since 6.0.0
57  */

58 public class CmsFlexController {
59
60     /** Constant for the controller request attribute name. */
61     public static final String JavaDoc ATTRIBUTE_NAME = "org.opencms.flex.CmsFlexController";
62
63     /** The log object for this class. */
64     private static final Log LOG = CmsLog.getLog(CmsFlexController.class);
65
66     /** The CmsFlexCache where the result will be cached in, required for the dispatcher. */
67     private CmsFlexCache m_cache;
68
69     /** The wrapped CmsObject provides JSP with access to the core system. */
70     private CmsObject m_cmsObject;
71
72     /** List of wrapped RequestContext info object. */
73     private List JavaDoc m_flexContextInfoList;
74
75     /** List of wrapped CmsFlexRequests. */
76     private List JavaDoc m_flexRequestList;
77
78     /** List of wrapped CmsFlexResponses. */
79     private List JavaDoc m_flexResponseList;
80
81     /** Indicates if this controller is currently in "forward" mode. */
82     private boolean m_forwardMode;
83
84     /** Wrapped top request. */
85     private HttpServletRequest JavaDoc m_req;
86
87     /** Wrapped top response. */
88     private HttpServletResponse JavaDoc m_res;
89
90     /** The CmsResource that was initialized by the original request, required for URI actions. */
91     private CmsResource m_resource;
92
93     /** Indicates if the respose should be streamed. */
94     private boolean m_streaming;
95
96     /** Exception that was caught during inclusion of sub elements. */
97     private Throwable JavaDoc m_throwable;
98
99     /** URI of a VFS resource that caused the exception. */
100     private String JavaDoc m_throwableResourceUri;
101
102     /** Indicates if the request is the top request. */
103     private boolean m_top;
104
105     /**
106      * Creates a new controller form the old one, exchaning just the provided OpenCms user context.<p>
107      *
108      * @param cms the OpenCms user context for this controller
109      * @param base the base controller
110      */

111     public CmsFlexController(CmsObject cms, CmsFlexController base) {
112
113         m_cmsObject = cms;
114         m_resource = base.m_resource;
115         m_cache = base.m_cache;
116         m_req = base.m_req;
117         m_res = base.m_res;
118         m_streaming = base.m_streaming;
119         m_top = base.m_top;
120         m_flexRequestList = base.m_flexRequestList;
121         m_flexResponseList = base.m_flexResponseList;
122         m_flexContextInfoList = base.m_flexContextInfoList;
123         m_forwardMode = base.m_forwardMode;
124         m_throwableResourceUri = base.m_throwableResourceUri;
125     }
126
127     /**
128      * Default constructor.<p>
129      *
130      * @param cms the initial CmsObject to wrap in the controller
131      * @param resource the file requested
132      * @param cache the instance of the flex cache
133      * @param req the current request
134      * @param res the current response
135      * @param streaming indicates if the response is streaming
136      * @param top indicates if the response is the top response
137      */

138     public CmsFlexController(
139         CmsObject cms,
140         CmsResource resource,
141         CmsFlexCache cache,
142         HttpServletRequest JavaDoc req,
143         HttpServletResponse JavaDoc res,
144         boolean streaming,
145         boolean top) {
146
147         m_cmsObject = cms;
148         m_resource = resource;
149         m_cache = cache;
150         m_req = req;
151         m_res = res;
152         m_streaming = streaming;
153         m_top = top;
154         m_flexRequestList = new Vector JavaDoc();
155         m_flexResponseList = new Vector JavaDoc();
156         m_flexContextInfoList = new Vector JavaDoc();
157         m_forwardMode = false;
158         m_throwableResourceUri = null;
159     }
160
161     /**
162      * Returns the wrapped CmsObject form the provided request, or <code>null</code> if the
163      * request is not running inside OpenCms.<p>
164      *
165      * @param req the current request
166      * @return the wrapped CmsObject
167      */

168     public static CmsObject getCmsObject(ServletRequest JavaDoc req) {
169
170         CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME);
171         if (controller != null) {
172             return controller.getCmsObject();
173         } else {
174             return null;
175         }
176     }
177
178     /**
179      * Returns the controller from the given request, or <code>null</code> if the
180      * request is not running inside OpenCms.<p>
181      *
182      * @param req the request to get the controller from
183      *
184      * @return the controller from the given request, or <code>null</code> if the request is not running inside OpenCms
185      */

186     public static CmsFlexController getController(ServletRequest JavaDoc req) {
187
188         return (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME);
189     }
190
191     /**
192      * Provides access to a root cause Exception that might have occured in a complex include scenario.<p>
193      *
194      * @param req the current request
195      * @return the root cause exception or null if no root cause exception is available
196      * @see #getThrowable()
197      */

198     public static Throwable JavaDoc getThrowable(ServletRequest JavaDoc req) {
199
200         CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME);
201         if (controller != null) {
202             return controller.getThrowable();
203         } else {
204             return null;
205         }
206     }
207
208     /**
209      * Provides access to URI of a VFS resource that caused an exception that might have occured in a complex inlucde scenario.<p>
210      *
211      * @param req the current request
212      * @return to URI of a VFS resource that caused an exception, or null
213      * @see #getThrowableResourceUri()
214      */

215     public static String JavaDoc getThrowableResourceUri(ServletRequest JavaDoc req) {
216
217         CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME);
218         if (controller != null) {
219             return controller.getThrowableResourceUri();
220         } else {
221             return null;
222         }
223     }
224
225     /**
226      * Checks if the provided request is running in OpenCms and the current users project is the online project.<p>
227      *
228      * @param req the current request
229      *
230      * @return <code>true</code> if the request is running in OpenCms and the current users project is
231      * the online project, <code>false</code> otherwise
232      */

233     public static boolean isCmsOnlineRequest(ServletRequest JavaDoc req) {
234
235         if (req == null) {
236             return false;
237         }
238         return getController(req).getCmsObject().getRequestContext().currentProject().isOnlineProject();
239     }
240
241     /**
242      * Checks if the provided request is running in OpenCms.<p>
243      *
244      * @param req the current request
245      * @return true if the request is running in OpenCms, false otherwise
246      */

247     public static boolean isCmsRequest(ServletRequest JavaDoc req) {
248
249         return ((req != null) && (req.getAttribute(ATTRIBUTE_NAME) != null));
250     }
251
252     /**
253      * Checks if the request has the "If-Modified-Since" header set, and if so,
254      * if the header date value is equal to the provided last modification date.<p>
255      *
256      * The "expires" information is automatically also checked since if a page recently
257      * expired, the date of last modification is set to the expiration date.<p>
258      *
259      * @param req the request to set the "If-Modified-Since" date header from
260      * @param dateLastModified the date to compare the header with
261      *
262      * @return <code>true</code> if the header is set and the header date is equal to the provided date
263      */

264     public static boolean isNotModifiedSince(HttpServletRequest JavaDoc req, long dateLastModified) {
265
266         // check if the request contains a last modified header
267
long lastModifiedHeader = req.getDateHeader(CmsRequestUtil.HEADER_IF_MODIFIED_SINCE);
268         // if last modified header is set (> -1), compare it to the requested resource
269
return ((lastModifiedHeader > -1) && (((dateLastModified / 1000) * 1000) == lastModifiedHeader));
270     }
271
272     /**
273      * Removes the controller attribute from a request.<p>
274      *
275      * @param req the request to remove the controller from
276      */

277     public static void removeController(ServletRequest JavaDoc req) {
278
279         CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME);
280         if (controller != null) {
281             controller.clear();
282         }
283     }
284
285     /**
286      * Stores the given controller in the given request (using a request attribute).<p>
287      *
288      * @param req the request where to store the controller in
289      * @param controller the controller to store
290      */

291     public static void setController(ServletRequest JavaDoc req, CmsFlexController controller) {
292
293         req.setAttribute(CmsFlexController.ATTRIBUTE_NAME, controller);
294     }
295
296     /**
297      * Sets the <code>Expires</code> date header for a given http request.<p>
298      *
299      * Also sets the <code>cache-control: max-age</code> header to the time of the expiration.
300      * A certain upper limit is imposed on the expiration date parameter to ensure the resources are
301      * not cached to long in proxies. This can be controlled by the <code>maxAge</code> parameter.
302      * If <code>maxAge</code> is lower then 0, then a default max age of 86400000 msec (1 day) is used.<p>
303      *
304      * @param res the reponse to set the "Expires" date header for
305      * @param maxAge maximum amount of time in milliseconds the response remains valid
306      * @param dateExpires the date to set (if this is not in the future, it is ignored)
307      */

308     public static void setDateExpiresHeader(HttpServletResponse JavaDoc res, long dateExpires, long maxAge) {
309
310         long now = System.currentTimeMillis();
311         if ((dateExpires > now) && (dateExpires != CmsResource.DATE_EXPIRED_DEFAULT)) {
312
313             // important: many caches (browsers or proxy) use the "Expires" header
314
// to avoid re-loading of pages that are not expired
315
// while this is right in general, no changes before the expiration date
316
// will be displayed
317
// therefore it is better to not use an expiration to far in the future
318

319             // if no valid max age is set, restrict it to 24 hrs
320
if (maxAge < 0L) {
321                 maxAge = 86400000;
322             }
323
324             if ((dateExpires - now) > maxAge) {
325                 // set "Expires" header max one day into the future
326
dateExpires = now + maxAge;
327             }
328             res.setDateHeader(CmsRequestUtil.HEADER_EXPIRES, dateExpires);
329
330             // setting the "Expires" header only is not sufficient - even expired documents seems to be cached
331
// therefore, the "cache-control: max-age" is also set
332
res.setHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MAX_AGE + (maxAge / 1000L));
333         }
334     }
335
336     /**
337      * Sets the "last modified" date header for a given http request.<p>
338      *
339      * @param res the reponse to set the "last modified" date header for
340      * @param dateLastModified the date to set (if this is lower then 0, the current time is set)
341      */

342     public static void setDateLastModifiedHeader(HttpServletResponse JavaDoc res, long dateLastModified) {
343
344         if (dateLastModified > -1) {
345             // set date last modified header (precision is only second, not millisecond
346
res.setDateHeader(CmsRequestUtil.HEADER_LAST_MODIFIED, (dateLastModified / 1000) * 1000);
347         } else {
348             // this resource can not be optimized for "last modified", use current time as header
349
res.setDateHeader(CmsRequestUtil.HEADER_LAST_MODIFIED, System.currentTimeMillis());
350         }
351     }
352
353     /**
354      * Clears all data of this controller.<p>
355      */

356     public void clear() {
357
358         if (m_flexRequestList != null) {
359             m_flexRequestList.clear();
360         }
361         m_flexRequestList = null;
362         if (m_flexResponseList != null) {
363             m_flexResponseList.clear();
364         }
365         m_flexResponseList = null;
366         if (m_req != null) {
367             m_req.removeAttribute(ATTRIBUTE_NAME);
368         }
369         m_req = null;
370         m_res = null;
371         m_cmsObject = null;
372         m_resource = null;
373         m_cache = null;
374         m_throwable = null;
375     }
376
377     /**
378      * Returns the CmsFlexCache instance where all results from this request will be cached in.<p>
379      *
380      * This is public so that pages like the Flex Cache Administration page
381      * have a way to access the cache object.<p>
382      *
383      * @return the CmsFlexCache instance where all results from this request will be cached in
384      */

385     public CmsFlexCache getCmsCache() {
386
387         return m_cache;
388     }
389
390     /**
391      * Returns the wrapped CmsObject.<p>
392      *
393      * @return the wrapped CmsObject
394      */

395     public CmsObject getCmsObject() {
396
397         return m_cmsObject;
398     }
399
400     /**
401      * This method provides access to the top-level CmsResource of the request
402      * which is of a type that supports the FlexCache,
403      * i.e. usually the CmsFile that is identical to the file uri requested by the user,
404      * not he current included element.<p>
405      *
406      * @return the requested top-level CmsFile
407      */

408     public CmsResource getCmsResource() {
409
410         return m_resource;
411     }
412
413     /**
414      * Returns the current flex request.<p>
415      *
416      * @return the current flex request
417      */

418     public CmsFlexRequest getCurrentRequest() {
419
420         return (CmsFlexRequest)m_flexRequestList.get(m_flexRequestList.size() - 1);
421     }
422
423     /**
424      * Returns the current flex response.<p>
425      *
426      * @return the current flex response
427      */

428     public CmsFlexResponse getCurrentResponse() {
429
430         return (CmsFlexResponse)m_flexResponseList.get(m_flexResponseList.size() - 1);
431     }
432
433     /**
434      * Returns the combined "expires" date for all resources read during this request.<p>
435      *
436      * @return the combined "expires" date for all resources read during this request
437      */

438     public long getDateExpires() {
439
440         int pos = m_flexContextInfoList.size() - 1;
441         if (pos < 0) {
442             // ensure a valid position is used
443
return CmsResource.DATE_EXPIRED_DEFAULT;
444         }
445         return ((CmsFlexRequestContextInfo)m_flexContextInfoList.get(pos)).getDateExpires();
446     }
447
448     /**
449      * Returns the combined "last modified" date for all resources read during this request.<p>
450      *
451      * @return the combined "last modified" date for all resources read during this request
452      */

453     public long getDateLastModified() {
454
455         int pos = m_flexContextInfoList.size() - 1;
456         if (pos < 0) {
457             // ensure a valid position is used
458
return CmsResource.DATE_RELEASED_DEFAULT;
459         }
460         return ((CmsFlexRequestContextInfo)m_flexContextInfoList.get(pos)).getDateLastModified();
461     }
462
463     /**
464      * Returns the size of the response stack.<p>
465      *
466      * @return the size of the response stack
467      */

468     public int getResponseStackSize() {
469
470         return m_flexResponseList.size();
471     }
472
473     /**
474      * Returns an exception (Throwable) that was caught during inclusion of sub elements,
475      * or null if no exceptions where thrown in sub elements.<p>
476      *
477      * @return an exception (Throwable) that was caught during inclusion of sub elements
478      */

479     public Throwable JavaDoc getThrowable() {
480
481         return m_throwable;
482     }
483
484     /**
485      * Returns the URI of a VFS resource that caused the exception that was caught during inclusion of sub elements,
486      * might return null if no URI information was available for the exception.<p>
487      *
488      * @return the URI of a VFS resource that caused the exception that was caught during inclusion of sub elements
489      */

490     public String JavaDoc getThrowableResourceUri() {
491
492         return m_throwableResourceUri;
493     }
494
495     /**
496      * Returns the current http request.<p>
497      *
498      * @return the current http request
499      */

500     public HttpServletRequest JavaDoc getTopRequest() {
501
502         return m_req;
503     }
504
505     /**
506      * Returns the current http response.<p>
507      *
508      * @return the current http response
509      */

510     public HttpServletResponse JavaDoc getTopResponse() {
511
512         return m_res;
513     }
514
515     /**
516      * Returns <code>true</code> if the controller does not yet contain any requests.<p>
517      *
518      * @return <code>true</code> if the controller does not yet contain any requests
519      */

520     public boolean isEmptyRequestList() {
521
522         return (m_flexRequestList != null) && m_flexRequestList.isEmpty();
523     }
524
525     /**
526      * Returns <code>true</code> if this controller is currently in "forward" mode.<p>
527      *
528      * @return <code>true</code> if this controller is currently in "forward" mode
529      */

530     public boolean isForwardMode() {
531
532         return m_forwardMode;
533     }
534
535     /**
536      * Returns <code>true</code> if the generated output of the response should
537      * be written to the stream directly.<p>
538      *
539      * @return <code>true</code> if the generated output of the response should be written to the stream directly
540      */

541     public boolean isStreaming() {
542
543         return m_streaming;
544     }
545
546     /**
547      * Returns <code>true</code> if this controller was generated as top level controller.<p>
548      *
549      * If a resource (e.g. a JSP) is processed and it's content is included in
550      * another resource, then this will be <code>false</code>.
551      *
552      * @return <code>true</code> if this controller was generated as top level controller
553      * @see org.opencms.loader.I_CmsResourceLoader#dump(CmsObject, CmsResource, String, java.util.Locale, HttpServletRequest, HttpServletResponse)
554      * @see org.opencms.jsp.CmsJspActionElement#getContent(String)
555      */

556     public boolean isTop() {
557
558         return m_top;
559     }
560
561     /**
562      * Removes the topmost request/response pair from the stack.<p>
563      */

564     public void pop() {
565
566         if ((m_flexRequestList != null) && !m_flexRequestList.isEmpty()) {
567             m_flexRequestList.remove(m_flexRequestList.size() - 1);
568         }
569         if ((m_flexResponseList != null) && !m_flexRequestList.isEmpty()) {
570             m_flexResponseList.remove(m_flexResponseList.size() - 1);
571         }
572         if ((m_flexContextInfoList != null) && !m_flexContextInfoList.isEmpty()) {
573             CmsFlexRequestContextInfo info = (CmsFlexRequestContextInfo)m_flexContextInfoList.remove(m_flexContextInfoList.size() - 1);
574             if (m_flexContextInfoList.size() > 0) {
575                 ((CmsFlexRequestContextInfo)m_flexContextInfoList.get(0)).merge(info);
576                 updateRequestContextInfo();
577             }
578         }
579     }
580
581     /**
582      * Adds another flex request/response pair to the stack.<p>
583      *
584      * @param req the request to add
585      * @param res the response to add
586      */

587     public void push(CmsFlexRequest req, CmsFlexResponse res) {
588
589         m_flexRequestList.add(req);
590         m_flexResponseList.add(res);
591         m_flexContextInfoList.add(new CmsFlexRequestContextInfo());
592         updateRequestContextInfo();
593     }
594
595     /**
596      * Sets the value of the "forward mode" flag.<p>
597      *
598      * @param value the forward mode to set
599      */

600     public void setForwardMode(boolean value) {
601
602         m_forwardMode = value;
603     }
604
605     /**
606      * Sets an exception (Throwable) that was caught during inclusion of sub elements.<p>
607      *
608      * If another exception is already set in this controller, then the additional exception
609      * is ignored.
610      *
611      * @param throwable the exception (Throwable) to set
612      * @param resource the URI of the VFS resource the error occured on (might be null if unknown)
613      * @return the exception stored in the contoller
614      */

615     public Throwable JavaDoc setThrowable(Throwable JavaDoc throwable, String JavaDoc resource) {
616
617         if (m_throwable == null) {
618             m_throwable = throwable;
619             m_throwableResourceUri = resource;
620         } else {
621             if (LOG.isDebugEnabled()) {
622                 if (resource != null) {
623                     LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCONTROLLER_IGNORED_EXCEPTION_1, resource));
624                 } else {
625                     LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCONTROLLER_IGNORED_EXCEPTION_0));
626                 }
627             }
628         }
629         return m_throwable;
630     }
631
632     /**
633      * Puts the response in a suspended state.<p>
634      */

635     public void suspendFlexResponse() {
636
637         for (int i = 0; i < m_flexResponseList.size(); i++) {
638             CmsFlexResponse res = (CmsFlexResponse)m_flexResponseList.get(i);
639             res.setSuspended(true);
640         }
641     }
642
643     /**
644      * Updates the "last modified" date and the "expires" date
645      * for all resources read during this request with the given values.<p>
646      *
647      * The currently stored value for "last modified" is only updated with the new value if
648      * the new value is either larger (i.e. newer) then the stored value,
649      * or if the new value is less then zero, which indicates that the "last modified"
650      * optimization can not be used because the element is dynamic.<p>
651      *
652      * The stored "expires" value is only updated if the new value is smaller
653      * then the stored value.<p>
654      *
655      * @param dateLastModified the value to update the "last modified" date with
656      * @param dateExpires the value to update the "expires" date with
657      */

658     public void updateDates(long dateLastModified, long dateExpires) {
659
660         int pos = m_flexContextInfoList.size() - 1;
661         if (pos < 0) {
662             // ensure a valid position is used
663
return;
664         }
665         ((CmsFlexRequestContextInfo)m_flexContextInfoList.get(pos)).updateDates(dateLastModified, dateExpires);
666     }
667
668     /**
669      * Updates the context info of the request context.<p>
670      */

671     private void updateRequestContextInfo() {
672
673         if ((m_flexContextInfoList != null) && !m_flexContextInfoList.isEmpty()) {
674             m_cmsObject.getRequestContext().setAttribute(
675                 CmsRequestUtil.HEADER_LAST_MODIFIED,
676                 m_flexContextInfoList.get(m_flexContextInfoList.size() - 1));
677         }
678     }
679 }
Popular Tags