View Javadoc

1   /*
2    * $Header: /usr/local/cvsroot/dev/madcache/src/com/macvu/tiles/taglib/CacheInsertTag.java,v 1.5 2004/05/06 02:18:54 macvu Exp $
3    * $Revision: 1.5 $
4    * $Date: 2004/05/06 02:18:54 $
5    *
6    * ====================================================================
7    *
8    * The Apache Software License, Version 1.1
9    *
10   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
11   * reserved.
12   *
13   * Redistribution and use in source and binary forms, with or without
14   * modification, are permitted provided that the following conditions
15   * are met:
16   *
17   * 1. Redistributions of source code must retain the above copyright
18   *    notice, this list of conditions and the following disclaimer.
19   *
20   * 2. Redistributions in binary form must reproduce the above copyright
21   *    notice, this list of conditions and the following disclaimer in
22   *    the documentation and/or other materials provided with the
23   *    distribution.
24   *
25   * 3. The end-user documentation included with the redistribution, if
26   *    any, must include the following acknowlegement:
27   *       "This product includes software developed by the
28   *        Apache Software Foundation (http://www.apache.org/)."
29   *    Alternately, this acknowlegement may appear in the software itself,
30   *    if and wherever such third-party acknowlegements normally appear.
31   *
32   * 4. The names "The Jakarta Project", "Struts", and "Apache Software
33   *    Foundation" must not be used to endorse or promote products derived
34   *    from this software without prior written permission. For written
35   *    permission, please contact apache@apache.org.
36   *
37   * 5. Products derived from this software may not be called "Apache"
38   *    nor may "Apache" appear in their names without prior written
39   *    permission of the Apache Group.
40   *
41   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52   * SUCH DAMAGE.
53   * ====================================================================
54   *
55   * This software consists of voluntary contributions made by many
56   * individuals on behalf of the Apache Software Foundation.  For more
57   * information on the Apache Software Foundation, please see
58   * <http://www.apache.org/>.
59   *
60   */
61  
62  package com.macvu.tiles.taglib;
63  
64  import com.macvu.tiles.CacheComponentDefinition;
65  import com.macvu.tiles.CacheInformation;
66  import com.macvu.tiles.cache.CacheObjectWrapper;
67  import com.macvu.tiles.capture.CacheHttpServletResponse;
68  import com.macvu.tiles.capture.CacheablesCaptureWrapper;
69  import org.apache.commons.logging.Log;
70  import org.apache.commons.logging.LogFactory;
71  import org.apache.struts.taglib.tiles.ComponentConstants;
72  import org.apache.struts.taglib.tiles.InsertTag;
73  import org.apache.struts.tiles.ComponentContext;
74  import org.apache.struts.tiles.ComponentDefinition;
75  import org.apache.struts.tiles.Controller;
76  import org.apache.struts.tiles.TilesUtil;
77  import org.apache.struts.util.ResponseUtils;
78  
79  import javax.servlet.ServletContext;
80  import javax.servlet.ServletException;
81  import javax.servlet.http.HttpServletRequest;
82  import javax.servlet.http.HttpServletResponse;
83  import javax.servlet.jsp.JspException;
84  import javax.servlet.jsp.PageContext;
85  import java.io.IOException;
86  import java.io.PrintWriter;
87  
88  public class CacheInsertTag extends InsertTag {
89  
90      protected static Log log = LogFactory.getLog(CacheInsertTag.class);
91  
92      /***
93       * Get current component context.
94       */
95      private ComponentContext getCurrentContext() {
96          if (cachedCurrentContext == null) {
97              cachedCurrentContext =
98                      (ComponentContext) pageContext.getAttribute(ComponentConstants.COMPONENT_CONTEXT,
99                              PageContext.REQUEST_SCOPE);
100         }
101         return cachedCurrentContext;
102     }
103 
104     /***
105      * End of Process tag attribute "definition".
106      * Overload definition with tag attributes "template" and "role".
107      * Then, create appropriate tag handler.
108      *
109      * @param definition Definition to process.
110      * @return Appropriate TagHandler.
111      * @throws JspException InstantiationException Can't create requested controller
112      */
113     protected TagHandler processDefinition(ComponentDefinition definition)
114             throws JspException {
115         // Declare local variable in order to not change Tag attribute values.
116         String role = this.role;
117         String page = this.page;
118         Controller controller = null;
119 
120         if (log.isDebugEnabled()) {
121             log.debug("Process Definition: " + definition.getName());
122         }
123         try {
124             controller = definition.getOrCreateController();
125 
126             // Overload definition with tag's template and role.
127             if (role == null) {
128                 role = definition.getRole();
129             }
130             if (page == null) {
131                 page = definition.getTemplate();
132             }
133             if (controllerName != null) {
134                 controller =
135                         ComponentDefinition.createController(controllerName,
136                                 controllerType);
137             }
138 
139             if (definition instanceof CacheComponentDefinition) {
140                 // Can check if page is set
141                 return new CacheInsertHandler((CacheComponentDefinition) definition,
142                         page,
143                         role,
144                         controller);
145             } else {
146                 // Can check if page is set
147                 return new InsertHandler(definition.getAttributes(),
148                         page,
149                         role,
150                         controller);
151             }
152         } catch (InstantiationException ex) {
153             throw new JspException(ex.getMessage());
154         }
155     }
156 
157     /***
158      * Do an include of specified page.
159      * This method is used internally to do all includes from this class. It delegates
160      * the include call to the TilesUtil.doInclude().
161      *
162      * @param page The page that will be included
163      * @throws ServletException - Thrown by call to pageContext.include()
164      * @throws IOException      - Thrown by call to pageContext.include()
165      */
166     protected void doInclude(String page, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) throws ServletException, IOException {
167         /*
168           TilesUtil.doInclude( page,
169                           (HttpServletRequest)pageContext.getRequest(),
170                           (HttpServletResponse)pageContext.getResponse(),
171                           pageContext.getServletContext());
172         */
173         TilesUtil.doInclude(page, request, response, servletContext);
174     }
175 
176     protected class CacheInsertHandler implements TagHandler {
177         protected CacheComponentDefinition definition;
178         protected String page;
179         protected ComponentContext currentContext;
180         protected ComponentContext subCompContext;
181         protected String role;
182         protected Controller controller;
183 
184         /***
185          * Constructor.
186          * Create insert handler using Component definition.
187          */
188         public CacheInsertHandler(CacheComponentDefinition definition,
189                                   String page,
190                                   String role,
191                                   Controller controller) {
192             this.definition = definition;
193             this.page = page;
194             this.role = role;
195             this.controller = controller;
196             subCompContext = new ComponentContext(definition.getAttributes());
197         }
198 
199         /***
200          * Create a new empty context.
201          */
202         public int doStartTag() throws JspException {
203             // Check role
204             if (role != null
205                     && !((HttpServletRequest) pageContext.getRequest()).isUserInRole(role)) {
206                 return SKIP_BODY;
207             }
208 
209             // save current context
210             this.currentContext = getCurrentContext();
211             return EVAL_BODY_INCLUDE;
212         }
213 
214         /***
215          * Add attribute to sub context.
216          * Do nothing.
217          */
218         public void putAttribute(String name, Object value) {
219             subCompContext.putAttribute(name, value);
220         }
221 
222         /***
223          * Include requested page.
224          */
225         public int doEndTag() throws JspException {
226             // Check role
227             if (role != null
228                     && !((HttpServletRequest) pageContext.getRequest()).isUserInRole(role)) {
229                 return EVAL_PAGE;
230             }
231 
232             try {
233                 if (log.isDebugEnabled()) {
234                     log.debug("insert page='" + page + "'.");
235                 }
236 
237                 HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
238                 HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
239                 ServletContext servletContext = pageContext.getServletContext();
240 
241                 //  Capture the Cacheable Information.
242                 CacheablesCaptureWrapper cacheables = new CacheablesCaptureWrapper(servletContext);
243                 if (cacheables.isEnableCapture()) {
244                     cacheables.captureCacheablesForTile((CacheComponentDefinition) definition, pageContext);
245                 }
246 
247                 CacheObjectWrapper cacheController = new CacheObjectWrapper();
248                 CacheInformation info = ((CacheComponentDefinition) definition).getCacheInformation();
249                 cacheController.initiateCacheInformation(pageContext.getServletContext(), info);
250                 if (cacheController.isCacheEnabled()) {
251                     String key = cacheController.getCacheKey((HttpServletRequest) pageContext.getRequest());
252                     if (log.isDebugEnabled()) {
253                         log.debug("Cache is enable.  Looking for key: " + key);
254                     }
255                     String cache = (String) cacheController.getCache(key);
256                     if (cache == null) {
257                         CacheHttpServletResponse cacheResponse = new CacheHttpServletResponse(response);
258                         performTileSection(request, cacheResponse, servletContext);
259                         cacheController.putCache(key, cacheResponse.getCache());
260                     } else {
261                         ResponseUtils.write(pageContext, cache);
262                     }
263                 } else {
264                     performTileSection(request, response, servletContext);
265                 }
266             } catch (IOException ex) {
267                 processException(ex,
268                         "Can't insert page '" + page + "' : " + ex.getMessage());
269 
270             } catch (IllegalArgumentException ex) { // Can't resolve page uri
271                 // Do we ignore bad page uri errors ?
272                 if (!(page == null && isErrorIgnored)) {
273                     // Don't ignore bad page uri errors
274                     processException(ex,
275                             "Tag 'insert' can't insert page '"
276                             + page
277                             + "'. Check if it exists.\n"
278                             + ex.getMessage());
279                 }
280 
281             } catch (ServletException ex) {
282                 Throwable realEx = ex;
283                 if (ex.getRootCause() != null) {
284                     realEx = ex.getRootCause();
285                 }
286                 processException(realEx,
287                         "[ServletException in:"
288                         + page
289                         + "] "
290                         + realEx.getMessage()
291                         + "'");
292 
293             } catch (Exception ex) {
294                 processException(ex,
295                         "[Exception in:" + page + "] " + ex.getMessage());
296 
297             } finally {
298                 // restore old context
299                 // done only if currentContext not null (bug with Silverstream ?; related by Arvindra Sehmi 20010712)
300                 if (currentContext != null) {
301                     pageContext.setAttribute(ComponentConstants.COMPONENT_CONTEXT,
302                             currentContext,
303                             PageContext.REQUEST_SCOPE);
304                 }
305             }
306             return EVAL_PAGE;
307         }
308 
309         private void performTileSection(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
310             if (log.isDebugEnabled()) {
311                 log.debug("performTileSection: Enter");
312             }
313             // set new context for included component.
314             pageContext.setAttribute(ComponentConstants.COMPONENT_CONTEXT,
315                     subCompContext,
316                     PageContext.REQUEST_SCOPE);
317 
318             // Call controller if any
319             if (controller != null) {
320                 controller.perform(subCompContext,
321                         request,
322                         response,
323                         context);
324             }
325 
326             // include requested component.
327             if (flush) {
328                 pageContext.getOut().flush();
329             }
330 
331             if (log.isDebugEnabled()) {
332                 log.debug("Do Include Page: " + page);
333             }
334             doInclude(page,
335                     request,
336                     response,
337                     context);
338         }
339 
340         /***
341          * Process an exception.
342          * Depending of debug attribute, print full exception trace or only
343          * its message in output page.
344          *
345          * @param ex  Exception
346          * @param msg An additional message to show in console and to propagate if we can't output exception.
347          */
348         protected void processException(Throwable ex, String msg)
349                 throws JspException {
350             try {
351                 if (msg == null) {
352                     msg = ex.getMessage();
353                 }
354                 if (log.isDebugEnabled()) { // show full trace
355                     log.debug(msg, ex);
356                     pageContext.getOut().println(msg);
357                     ex.printStackTrace(new PrintWriter(pageContext.getOut(), true));
358                 } else { // show only message
359                     pageContext.getOut().println(msg);
360                 }
361             } catch (IOException ioex) { // problems. Propagate original exception
362                 pageContext.setAttribute(ComponentConstants.EXCEPTION_KEY,
363                         ex,
364                         PageContext.REQUEST_SCOPE);
365                 throw new JspException(msg);
366             }
367         }
368     }
369 
370 }