View Javadoc

1   /*
2    * $Id: ActionContextCleanUp.java 651946 2008-04-27 13:41:38Z apetrelli $
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   * @see FilterDispatcher
63   * @see Dispatcher
64   *
65   * @version $Date: 2008-04-27 08:41:38 -0500 (Sun, 27 Apr 2008) $ $Id: ActionContextCleanUp.java 651946 2008-04-27 13:41:38Z apetrelli $
66   */
67  public class ActionContextCleanUp implements Filter {
68  
69      private static final Logger LOG = LoggerFactory.getLogger(ActionContextCleanUp.class);
70  
71      private static final String COUNTER = "__cleanup_recursion_counter";
72  
73      /***
74       * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
75       */
76      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
77  
78          HttpServletRequest request = (HttpServletRequest) req;
79          HttpServletResponse response = (HttpServletResponse) res;
80  
81          String timerKey = "ActionContextCleanUp_doFilter: ";
82          try {
83              UtilTimerStack.push(timerKey);
84  
85              try {
86                  Integer count = (Integer)request.getAttribute(COUNTER);
87                  if (count == null) {
88                      count = Integer.valueOf(1);
89                  }
90                  else {
91                      count = Integer.valueOf(count.intValue()+1);
92                  }
93                  request.setAttribute(COUNTER, count);
94  
95                  //LOG.debug("filtering counter="+count);
96  
97                  chain.doFilter(request, response);
98              } finally {
99                  int counterVal = ((Integer)request.getAttribute(COUNTER)).intValue();
100                 counterVal -= 1;
101                 request.setAttribute(COUNTER, Integer.valueOf(counterVal));
102                 cleanUp(request);
103             }
104         }
105         finally {
106             UtilTimerStack.pop(timerKey);
107         }
108     }
109 
110     /***
111      * Clean up the request of threadlocals if this is the last execution
112      *
113      * @param req The servlet request
114      */
115     protected static void cleanUp(ServletRequest req) {
116         // should we clean up yet?
117         Integer count = (Integer) req.getAttribute(COUNTER);
118         if (count != null && count > 0 ) {
119             if (LOG.isDebugEnabled()) {
120                 LOG.debug("skipping cleanup counter="+count);
121             }
122             return;
123         }
124 
125         // always dontClean up the thread request, even if an action hasn't been executed
126         ActionContext.setContext(null);
127         Dispatcher.setInstance(null);
128     }
129 
130     public void destroy() {
131     }
132 
133     public void init(FilterConfig arg0) throws ServletException {
134     }
135 }