Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/opencms/flex/cache/CmsFlexRequestDispatcher.java


1   /*
2    * File   : $Source: /usr/local/cvs/opencms/src/com/opencms/flex/cache/Attic/CmsFlexRequestDispatcher.java,v $
3    * Date   : $Date: 2003/05/13 13:18:20 $
4    * Version: $Revision: 1.7.2.1 $
5    *
6    * This library is part of OpenCms -
7    * the Open Source Content Mananagement System
8    *
9    * Copyright (C) 2002 - 2003 Alkacon Software (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, 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 com.opencms.flex.cache;
33  
34  import com.opencms.boot.I_CmsLogChannels;
35  import com.opencms.core.A_OpenCms;
36  import com.opencms.core.CmsException;
37  import com.opencms.file.CmsObject;
38  
39  import java.io.IOException;
40  
41  import javax.servlet.RequestDispatcher;
42  import javax.servlet.ServletException;
43  import javax.servlet.ServletRequest;
44  import javax.servlet.ServletResponse;
45  import javax.servlet.http.HttpServletRequest;
46  import javax.servlet.http.HttpServletResponse;
47  
48  /** 
49   * Implementation of the javax.servlet.RequestDispatcher interface to allow JSPs to be loaded
50   * from OpenCms.<p>
51   * 
52   * This dispatcher will load data from 3 different data sources:
53   * <ol>
54   * <li>Form the "real" system Filesystem (e.g. for JSP pages)
55   * <li>From the OpenCms VFS
56   * <li>From the Flex cache
57   * </ol>
58   *
59   * @author Alexander Kandzior (a.kandzior@alkacon.com)
60   * @version $Revision: 1.7.2.1 $
61   */
62  public class CmsFlexRequestDispatcher implements RequestDispatcher {
63          
64      /** The "real" RequestDispatcher, used when a true include (to the file system) is needed. */    
65      private RequestDispatcher m_rd = null;
66      
67      /** The OpenCms VFS target that will be included by the RequestDispatcher. */    
68      private String m_vfs_target = null;    
69      
70      /** The external target that will be included by the RequestDispatcher, needed if this is not a dispatcher to a cms resource */    
71      private String m_ext_target = null;
72      
73      /** Internal DEBUG flag. Set to 9 for maximum verbosity. */
74      private static final int DEBUG = 0;    
75  
76      /** 
77       * Creates a new instance of CmsFlexRequestDispatcher.<p>
78       *
79       * @param rd the "real" dispatcher, used for include call to file system
80       * @param vfs_target the cms resource that represents the external target
81       * @param ext_target the external target that the request will be dispatched to
82       */
83      public CmsFlexRequestDispatcher(
84          RequestDispatcher rd, 
85          String vfs_target, 
86          String ext_target
87      ) {
88          m_rd = rd;
89          m_vfs_target = vfs_target;
90          m_ext_target = ext_target;
91      } 
92  
93      /** 
94       * Wrapper for the standard servlet API call.<p>
95       * 
96       * Forward calls are actually NOT wrapped by OpenCms as of now.
97       * So they should not be used in JSP pages or servlets.<p>
98       *
99       * @param req the servlet request
100      * @param res the servlet response
101      * @throws ServletException in case something goes wrong
102      * @throws IOException in case something goes wrong
103      *
104      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
105      */ 
106     public void forward(
107         ServletRequest req, 
108         ServletResponse res
109     ) throws ServletException, IOException {
110         m_rd.forward(req, res);
111     }
112     
113     /** 
114      * Wrapper for dispatching to a file from the OpenCms VFS.<p>
115      *
116      * This method will dispatch to cache, to real file system or
117      * to the OpenCms VFS, whatever is needed.<p>
118      *
119      * This method is much more complex then it sould be because of the internal standard 
120      * buffering of JSP pages.
121      * Because of that I can not just intercept and buffer the stream, since I don't have 
122      * access to it (it is wrapped internally in the JSP pages, which have their own buffer).
123      * That leads to a solution where the data is first written to the bufferd stream, 
124      * but without includes. Then it is parsed again later 
125      * (in response.processCacheEntry()), enriched with the 
126      * included elements that have been ommitted in the first case.
127      * I would love to see a simpler solution, but this works for now.<p>
128      *
129      * @param req the servlet request
130      * @param res the servlet response
131      * @throws ServletException in case something goes wrong
132      * @throws IOException in case something goes wrong
133      */ 
134     public void include(
135         ServletRequest req, 
136         ServletResponse res
137     ) throws ServletException, IOException {
138             
139         if (DEBUG > 0) System.err.println("FlexDispatcher: Include called with target=" + m_vfs_target + " (ext_target=" + m_ext_target + ")");      
140         CmsFlexController controller = (CmsFlexController)req.getAttribute(CmsFlexController.ATTRIBUTE_NAME);
141         CmsObject cms = controller.getCmsObject();
142                 
143         if ((m_ext_target == null) && (controller != null)) {
144             // Check if the file exists in the VFS, if not set external target
145             try {
146                 cms.readFileHeader(m_vfs_target);
147             } catch (CmsException e) {
148                 if (e.getType() == CmsException.C_NOT_FOUND) {
149                     // File not found in VFS, treat it as external file
150                     m_ext_target = m_vfs_target;
151                 }
152             }
153         }
154                 
155         if ((m_ext_target != null) || (controller == null)) {
156             // This is an external include, probably to a JSP page, dispatch with system dispatcher
157             if (DEBUG > 0) System.err.println("FlexDispatcher: Dispatching to external target " + m_ext_target);      
158             m_rd.include(req, res);   
159             return;
160         }
161         
162         CmsFlexCache cache = controller.getCmsCache();
163         
164         // this is a request through the CMS
165         CmsFlexRequest f_req = controller.getCurrentRequest();
166         CmsFlexResponse f_res = controller.getCurrentResponse();
167         
168         if (f_req.containsIncludeCall(m_vfs_target)) {
169             // This resource was already included earlier, so we have a (probably endless) inclusion loop
170             throw new ServletException("FlexDispatcher: Dectected inclusion loop for target " + m_vfs_target);
171         } else {     
172             f_req.addInlucdeCall(m_vfs_target);
173         }
174        
175         // Do nothing if response is already finished (probably as a result of an earlier redirect)
176         if (f_res.isSuspended()) return;
177         
178         // Indicate to response that all further output or headers are result of include calls
179         f_res.setCmsIncludeMode(true);
180                 
181         // Create wrapper for request & response
182         CmsFlexRequest w_req = new CmsFlexRequest((HttpServletRequest)req, controller, m_vfs_target);
183         CmsFlexResponse w_res = new CmsFlexResponse((HttpServletResponse)res, controller); 
184         
185         // Push req/res to controller queue
186         controller.pushRequest(w_req);
187         controller.pushResponse(w_res);             
188         
189         CmsFlexCacheEntry entry = null;
190         if (f_req.isCacheable()) {
191             // Caching is on, check if requested resource is already in cache            
192             entry = cache.get(w_req.getCmsCacheKey());
193             if (entry != null) {
194                 // The target is already in the cache
195                 try {
196                     if (DEBUG > 0) System.err.println("FlexDispatcher: Loading file from cache for " + m_vfs_target);
197                     entry.service(w_req, w_res);
198                 } catch (com.opencms.core.CmsException e) {
199                     throw new ServletException("FlexDispatcher: Error while loading file from cache for " + m_vfs_target + "\n" + e, e);
200                 }                       
201             } else { 
202                 // Cache is on and resource is not yet cached, so we need to read the cache key for the response
203                 CmsFlexCacheKey res_key = cache.getKey(CmsFlexCacheKey.getKeyName(m_vfs_target, w_req.isOnline()));            
204                 if (res_key != null) {
205                     // Key already in cache, reuse it
206                     w_res.setCmsCacheKey(res_key);                                             
207                 } else {                                
208                     // Cache key is unknown, read key from properties
209                     String cacheProperty = null;
210                     try {
211                         // Read caching property from requested VFS resource                                     
212                         cacheProperty = cms.readProperty(m_vfs_target, com.opencms.flex.I_CmsResourceLoader.C_LOADER_CACHEPROPERTY);                    
213                         cache.putKey(w_res.setCmsCacheKey(m_vfs_target, cacheProperty, f_req.isOnline()));                                            
214                     } catch (com.opencms.core.CmsException e) {
215                         if (e.getType() == CmsException.C_FLEX_CACHE) {
216                             // Invalid key is ignored but logged, used key is cache=never
217                             if (I_CmsLogChannels.C_LOGGING && A_OpenCms.isLogging(I_CmsLogChannels.C_OPENCMS_INFO)) 
218                                 A_OpenCms.log(I_CmsLogChannels.C_OPENCMS_INFO, "[FlexCache] Invalid cache key for external resource \"" + m_vfs_target + "\": " + cacheProperty);
219                             // There will be a vaild key in the response ("cache=never") even after an exception
220                             cache.putKey(w_res.getCmsCacheKey());
221                         } else {
222                             // All other errors are not handled here
223                             throw new ServletException("FlexDispatcher: Error while loading cache properties for " + m_vfs_target + "\n" + e, e);
224                         }
225                     }                
226                     if (DEBUG > 1) System.err.println("FlexDispatcher: Cache properties for file " + m_vfs_target + " are: " + cacheProperty);
227                 }
228             }
229         }
230 
231         if (entry == null) {
232             // The target is not cached (or caching off), so load it with the internal resource loader
233             com.opencms.launcher.CmsLauncherManager manager = cms.getLauncherManager();
234             com.opencms.flex.I_CmsResourceLoader loader = null;
235 
236             String variation = null;
237             // Check cache keys to see if the result can be cached 
238             if (w_req.isCacheable()) variation = w_res.getCmsCacheKey().matchRequestKey(w_req.getCmsCacheKey());
239             // Indicate to the response if caching is not required
240             w_res.setCmsCachingRequired(variation != null);
241                         
242             com.opencms.file.CmsResource resource = null;
243             try {
244                 resource = cms.readFileHeader(m_vfs_target);
245                 int type = resource.getLauncherType();
246                 if (DEBUG > 0) System.err.println("FlexDispatcher: Loading resource type " + type);
247                 loader = (com.opencms.flex.I_CmsResourceLoader)manager.getLauncher(type);
248             } catch (java.lang.ClassCastException e) {
249                 throw new ServletException("FlexDispatcher: CmsResourceLoader interface not implemented for cms resource " + m_vfs_target + "\n" + e, e);
250             } catch (com.opencms.core.CmsException e) {
251                 // File might not exist or no read permissions
252                 throw new ServletException("FlexDispatcher: Error while reading header for cms resource " + m_vfs_target + "\n" + e, e);
253             }
254                      
255             if (DEBUG > 0) System.err.println("FlexDispatcher: Internal call, loading file using loader.service() for " + m_vfs_target);
256             loader.service(cms, resource, w_req, w_res);
257 
258             entry = w_res.processCacheEntry(); 
259             if ((entry != null) && (variation != null) && w_req.isCacheable()) {                                      
260                 cache.put(w_res.getCmsCacheKey(), entry, variation);                        
261             }                
262         }          
263         
264         if (f_res.hasIncludeList()) {
265             // Special case: This indicates that the output was not yet displayed
266             java.util.Map headers = w_res.getHeaders();
267             byte[] result = w_res.getWriterBytes();
268             if (DEBUG > 3) System.err.println("Non-display include call - Result of include is:\n" + new String(result));
269             CmsFlexResponse.processHeaders(headers, f_res);
270             f_res.addToIncludeResults(result);                    
271         }              
272 
273         // Indicate to response that include is finished
274         f_res.setCmsIncludeMode(false);
275         f_req.removeIncludeCall(m_vfs_target);      
276           
277         // Pop req/res from controller queue
278         controller.popRequest();
279         controller.popResponse();            
280     }
281 }