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