View Javadoc

    1   /*
    2    * $Id: ActionContextCleanUp.java 484717 2006-12-08 19:57:59Z 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  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                  //LOG.debug("filtering counter="+count);
    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         // should we clean up yet?
    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         // always dontClean up the thread request, even if an action hasn't been executed
    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 }