View Javadoc

1   /*
2    * $Id: ActionContextCleanUp.java 484717 2006-12-08 19:57:59Z mrdon $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.dispatcher;
22  
23  import java.io.IOException;
24  
25  import javax.servlet.Filter;
26  import javax.servlet.FilterChain;
27  import javax.servlet.FilterConfig;
28  import javax.servlet.ServletException;
29  import javax.servlet.ServletRequest;
30  import javax.servlet.ServletResponse;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  import com.opensymphony.xwork2.ActionContext;
38  import com.opensymphony.xwork2.ObjectFactory;
39  import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
40  
41  /***
42   * <!-- SNIPPET START: description -->
43   * Special filter designed to work with the {@link FilterDispatcher} and allow
44   * for easier integration with SiteMesh. Normally, ordering your filters to have
45   * SiteMesh go first, and then {@link FilterDispatcher} go second is perfectly fine.
46   * However, sometimes you may wish to access Struts features, including the
47   * value stack, from within your SiteMesh decorators. Because {@link FilterDispatcher}
48   * cleans up the {@link ActionContext}, your decorator won't have access to the
49   * data you want.
50   * <p/>
51   * <p/>
52   * By adding this filter, the {@link FilterDispatcher} will know to not clean up and
53   * instead defer cleanup to this filter. The ordering of the filters should then be:
54   * <p/>
55   * <ul>
56   * <li>this filter</li>
57   * <li>SiteMesh filter</li>
58   * <li>{@link FilterDispatcher}</li>
59   * </ul>
60   * <!-- SNIPPET END: description -->
61   *
62   *
63   * @see FilterDispatcher
64   * @see AbstractFilter
65   * @see Dispatcher
66   *
67   * @version $Date: 2006-12-08 14:57:59 -0500 (Fri, 08 Dec 2006) $ $Id: ActionContextCleanUp.java 484717 2006-12-08 19:57:59Z mrdon $
68   */
69  public class ActionContextCleanUp implements Filter {
70  
71      private static final Log LOG = LogFactory.getLog(ActionContextCleanUp.class);
72  
73      private static final String COUNTER = "__cleanup_recursion_counter";
74  
75      /***
76       * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
77       */
78      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
79  
80          HttpServletRequest request = (HttpServletRequest) req;
81          HttpServletResponse response = (HttpServletResponse) res;
82  
83          String timerKey = "ActionContextCleanUp_doFilter: ";
84          try {
85              UtilTimerStack.push(timerKey);
86  
87              try {
88                  Integer count = (Integer)request.getAttribute(COUNTER);
89                  if (count == null) {
90                      count = new Integer(1);
91                  }
92                  else {
93                      count = new Integer(count.intValue()+1);
94                  }
95                  request.setAttribute(COUNTER, count);
96  
97                  //LOG.debug("filtering counter="+count);
98  
99                  chain.doFilter(request, response);
100             } finally {
101                 int counterVal = ((Integer)request.getAttribute(COUNTER)).intValue();
102                 counterVal -= 1;
103                 request.setAttribute(COUNTER, new Integer(counterVal));
104                 cleanUp(request);
105             }
106         }
107         finally {
108             UtilTimerStack.pop(timerKey);
109         }
110     }
111 
112     /***
113      * Clean up the request of threadlocals if this is the last execution
114      *
115      * @param req The servlet request
116      */
117     protected static void cleanUp(ServletRequest req) {
118         // should we clean up yet?
119         Integer count = (Integer) req.getAttribute(COUNTER);
120         if (count != null && count > 0 ) {
121             if (LOG.isDebugEnabled()) {
122                 LOG.debug("skipping cleanup counter="+count);
123             }
124             return;
125         }
126 
127         // always dontClean up the thread request, even if an action hasn't been executed
128         ActionContext.setContext(null);
129         Dispatcher.setInstance(null);
130     }
131 
132     public void destroy() {
133     }
134 
135     public void init(FilterConfig arg0) throws ServletException {
136     }
137 }