1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
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
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 }