View Javadoc

1   /*
2    * $Id: ActionContextCleanUp.java 674498 2008-07-07 14:10:42Z 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  
22  package org.apache.struts2.dispatcher;
23  
24  import java.io.IOException;
25  
26  import javax.servlet.Filter;
27  import javax.servlet.FilterChain;
28  import javax.servlet.FilterConfig;
29  import javax.servlet.ServletException;
30  import javax.servlet.ServletRequest;
31  import javax.servlet.ServletResponse;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  
35  import com.opensymphony.xwork2.ActionContext;
36  import com.opensymphony.xwork2.util.logging.Logger;
37  import com.opensymphony.xwork2.util.logging.LoggerFactory;
38  import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
39  
40  /***
41   * <!-- SNIPPET START: description -->
42   * Special filter designed to work with the {@link FilterDispatcher} and allow
43   * for easier integration with SiteMesh. Normally, ordering your filters to have
44   * SiteMesh go first, and then {@link FilterDispatcher} go second is perfectly fine.
45   * However, sometimes you may wish to access Struts features, including the
46   * value stack, from within your SiteMesh decorators. Because {@link FilterDispatcher}
47   * cleans up the {@link ActionContext}, your decorator won't have access to the
48   * data you want.
49   * <p/>
50   * <p/>
51   * By adding this filter, the {@link FilterDispatcher} will know to not clean up and
52   * instead defer cleanup to this filter. The ordering of the filters should then be:
53   * <p/>
54   * <ul>
55   * <li>this filter</li>
56   * <li>SiteMesh filter</li>
57   * <li>{@link FilterDispatcher}</li>
58   * </ul>
59   * <!-- SNIPPET END: description -->
60   *
61   *
62   * @deprecated Since Struts 2.1.3, use {@link org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter} and
63   * {@link org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter} to use other Servlet filters that need access to
64   * the ActionContext
65   * @see FilterDispatcher
66   * @see Dispatcher
67   * @see org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter
68   * @see org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter
69   *
70   * @version $Date: 2008-07-07 10:10:42 -0400 (Mon, 07 Jul 2008) $ $Id: ActionContextCleanUp.java 674498 2008-07-07 14:10:42Z mrdon $
71   */
72  public class ActionContextCleanUp implements Filter {
73  
74      private static final Logger LOG = LoggerFactory.getLogger(ActionContextCleanUp.class);
75  
76      private static final String COUNTER = "__cleanup_recursion_counter";
77  
78      /***
79       * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
80       */
81      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
82  
83          HttpServletRequest request = (HttpServletRequest) req;
84          HttpServletResponse response = (HttpServletResponse) res;
85  
86          String timerKey = "ActionContextCleanUp_doFilter: ";
87          try {
88              UtilTimerStack.push(timerKey);
89  
90              try {
91                  Integer count = (Integer)request.getAttribute(COUNTER);
92                  if (count == null) {
93                      count = Integer.valueOf(1);
94                  }
95                  else {
96                      count = Integer.valueOf(count.intValue()+1);
97                  }
98                  request.setAttribute(COUNTER, count);
99  
100                 //LOG.debug("filtering counter="+count);
101 
102                 chain.doFilter(request, response);
103             } finally {
104                 int counterVal = ((Integer)request.getAttribute(COUNTER)).intValue();
105                 counterVal -= 1;
106                 request.setAttribute(COUNTER, Integer.valueOf(counterVal));
107                 cleanUp(request);
108             }
109         }
110         finally {
111             UtilTimerStack.pop(timerKey);
112         }
113     }
114 
115     /***
116      * Clean up the request of threadlocals if this is the last execution
117      *
118      * @param req The servlet request
119      */
120     protected static void cleanUp(ServletRequest req) {
121         // should we clean up yet?
122         Integer count = (Integer) req.getAttribute(COUNTER);
123         if (count != null && count > 0 ) {
124             if (LOG.isDebugEnabled()) {
125                 LOG.debug("skipping cleanup counter="+count);
126             }
127             return;
128         }
129 
130         // always dontClean up the thread request, even if an action hasn't been executed
131         ActionContext.setContext(null);
132         Dispatcher.setInstance(null);
133     }
134 
135     public void destroy() {
136     }
137 
138     public void init(FilterConfig arg0) throws ServletException {
139     }
140 }