001: /*
002: * $Id: ActionContextCleanUp.java 484717 2006-12-08 19:57:59Z mrdon $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.dispatcher;
022:
023: import java.io.IOException;
024:
025: import javax.servlet.Filter;
026: import javax.servlet.FilterChain;
027: import javax.servlet.FilterConfig;
028: import javax.servlet.ServletException;
029: import javax.servlet.ServletRequest;
030: import javax.servlet.ServletResponse;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036:
037: import com.opensymphony.xwork2.ActionContext;
038: import com.opensymphony.xwork2.ObjectFactory;
039: import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
040:
041: /**
042: * <!-- SNIPPET START: description -->
043: * Special filter designed to work with the {@link FilterDispatcher} and allow
044: * for easier integration with SiteMesh. Normally, ordering your filters to have
045: * SiteMesh go first, and then {@link FilterDispatcher} go second is perfectly fine.
046: * However, sometimes you may wish to access Struts features, including the
047: * value stack, from within your SiteMesh decorators. Because {@link FilterDispatcher}
048: * cleans up the {@link ActionContext}, your decorator won't have access to the
049: * data you want.
050: * <p/>
051: * <p/>
052: * By adding this filter, the {@link FilterDispatcher} will know to not clean up and
053: * instead defer cleanup to this filter. The ordering of the filters should then be:
054: * <p/>
055: * <ul>
056: * <li>this filter</li>
057: * <li>SiteMesh filter</li>
058: * <li>{@link FilterDispatcher}</li>
059: * </ul>
060: * <!-- SNIPPET END: description -->
061: *
062: *
063: * @see FilterDispatcher
064: * @see AbstractFilter
065: * @see Dispatcher
066: *
067: * @version $Date: 2006-12-08 14:57:59 -0500 (Fri, 08 Dec 2006) $ $Id: ActionContextCleanUp.java 484717 2006-12-08 19:57:59Z mrdon $
068: */
069: public class ActionContextCleanUp implements Filter {
070:
071: private static final Log LOG = LogFactory
072: .getLog(ActionContextCleanUp.class);
073:
074: private static final String COUNTER = "__cleanup_recursion_counter";
075:
076: /**
077: * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
078: */
079: public void doFilter(ServletRequest req, ServletResponse res,
080: FilterChain chain) throws IOException, ServletException {
081:
082: HttpServletRequest request = (HttpServletRequest) req;
083: HttpServletResponse response = (HttpServletResponse) res;
084:
085: String timerKey = "ActionContextCleanUp_doFilter: ";
086: try {
087: UtilTimerStack.push(timerKey);
088:
089: try {
090: Integer count = (Integer) request.getAttribute(COUNTER);
091: if (count == null) {
092: count = new Integer(1);
093: } else {
094: count = new Integer(count.intValue() + 1);
095: }
096: request.setAttribute(COUNTER, count);
097:
098: //LOG.debug("filtering counter="+count);
099:
100: chain.doFilter(request, response);
101: } finally {
102: int counterVal = ((Integer) request
103: .getAttribute(COUNTER)).intValue();
104: counterVal -= 1;
105: request.setAttribute(COUNTER, new Integer(counterVal));
106: cleanUp(request);
107: }
108: } finally {
109: UtilTimerStack.pop(timerKey);
110: }
111: }
112:
113: /**
114: * Clean up the request of threadlocals if this is the last execution
115: *
116: * @param req The servlet request
117: */
118: protected static void cleanUp(ServletRequest req) {
119: // should we clean up yet?
120: Integer count = (Integer) req.getAttribute(COUNTER);
121: if (count != null && count > 0) {
122: if (LOG.isDebugEnabled()) {
123: LOG.debug("skipping cleanup counter=" + count);
124: }
125: return;
126: }
127:
128: // always dontClean up the thread request, even if an action hasn't been executed
129: ActionContext.setContext(null);
130: Dispatcher.setInstance(null);
131: }
132:
133: public void destroy() {
134: }
135:
136: public void init(FilterConfig arg0) throws ServletException {
137: }
138: }
|