View Javadoc

1   /*
2    * $Id: DefaultActionSupport.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  package org.apache.struts2.dispatcher.ng;
22  
23  import org.apache.struts2.dispatcher.Dispatcher;
24  import org.apache.struts2.dispatcher.mapper.ActionMapping;
25  import org.apache.struts2.dispatcher.mapper.ActionMapper;
26  import org.apache.struts2.StrutsException;
27  import org.apache.struts2.RequestUtils;
28  
29  import javax.servlet.ServletException;
30  import javax.servlet.ServletContext;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import com.opensymphony.xwork2.ActionContext;
35  import com.opensymphony.xwork2.util.ValueStack;
36  import com.opensymphony.xwork2.util.ValueStackFactory;
37  import com.opensymphony.xwork2.util.logging.Logger;
38  import com.opensymphony.xwork2.util.logging.LoggerFactory;
39  
40  import java.io.IOException;
41  import java.util.HashMap;
42  import java.util.List;
43  import java.util.regex.Pattern;
44  
45  /***
46   * Contains preparation operations for a request before execution
47   */
48  public class PrepareOperations {
49  
50      private ServletContext servletContext;
51      private Dispatcher dispatcher;
52      private static final String STRUTS_ACTION_MAPPING_KEY = "struts.actionMapping";
53      public static final String CLEANUP_RECURSION_COUNTER = "__cleanup_recursion_counter";
54      private Logger log = LoggerFactory.getLogger(PrepareOperations.class);
55  
56      public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher) {
57          this.dispatcher = dispatcher;
58          this.servletContext = servletContext;
59      }
60  
61      /***
62       * Creates the action context and initializes the thread local
63       */
64      public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
65          ActionContext ctx;
66          Integer counter = 1;
67          Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
68          if (oldCounter != null) {
69              counter = oldCounter + 1;
70          }
71          
72          ActionContext oldContext = ActionContext.getContext();
73          if (oldContext != null) {
74              // detected existing context, so we are probably in a forward
75              ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
76          } else {
77              ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
78              stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
79              ctx = new ActionContext(stack.getContext());
80          }
81          request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
82          ActionContext.setContext(ctx);
83          return ctx;
84      }
85  
86      /***
87       * Cleans up a request of thread locals
88       */
89      public void cleanupRequest(HttpServletRequest request) {
90          Integer counterVal = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
91          if (counterVal != null) {
92              counterVal -= 1;
93              request.setAttribute(CLEANUP_RECURSION_COUNTER, counterVal);
94              if (counterVal > 0 ) {
95                  if (log.isDebugEnabled()) {
96                      log.debug("skipping cleanup counter="+counterVal);
97                  }
98                  return;
99              }
100         }
101 
102         // always clean up the thread request, even if an action hasn't been executed
103         ActionContext.setContext(null);
104         Dispatcher.setInstance(null);
105     }
106 
107     /***
108      * Assigns the dispatcher to the dispatcher thread local
109      */
110     public void assignDispatcherToThread() {
111         Dispatcher.setInstance(dispatcher);
112     }
113 
114     /***
115      * Sets the request encoding and locale on the response
116      */
117     public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {
118         dispatcher.prepare(request, response);
119     }
120 
121     /***
122      * Wraps the request with the Struts wrapper that handles multipart requests better
123      * @return The new request, if there is one
124      * @throws ServletException
125      */
126     public HttpServletRequest wrapRequest(HttpServletRequest oldRequest) throws ServletException {
127         HttpServletRequest request = oldRequest;
128         try {
129             // Wrap request first, just in case it is multipart/form-data
130             // parameters might not be accessible through before encoding (ww-1278)
131             request = dispatcher.wrapRequest(request, servletContext);
132         } catch (IOException e) {
133             String message = "Could not wrap servlet request with MultipartRequestWrapper!";
134             throw new ServletException(message, e);
135         }
136         return request;
137     }
138 
139     /***
140      *   Finds and optionally creates an {@link ActionMapping}.  It first looks in the current request to see if one
141      * has already been found, otherwise, it creates it and stores it in the request.  No mapping will be created in the
142      * case of static resource requests or unidentifiable requests for other servlets, for example.
143      */
144     public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response) {
145         return findActionMapping(request, response, false);
146     }
147 
148     /***
149      * Finds and optionally creates an {@link ActionMapping}.  if forceLookup is false, it first looks in the current request to see if one
150      * has already been found, otherwise, it creates it and stores it in the request.  No mapping will be created in the
151      * case of static resource requests or unidentifiable requests for other servlets, for example.
152      * @param forceLookup if true, the action mapping will be looked up from the ActionMapper instance, ignoring if there is one
153      * in the request or not 
154      */
155     public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
156         ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
157         if (mapping == null || forceLookup) {
158             try {
159                 mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
160                 if (mapping != null) {
161                     request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
162                 }
163             } catch (Exception ex) {
164                 dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
165             }
166         }
167 
168         return mapping;
169     }
170 
171     /***
172      * Cleans up the dispatcher instance
173      */
174     public void cleanupDispatcher() {
175         if (dispatcher == null) {
176             throw new StrutsException("something is seriously wrong, Dispatcher is not initialized (null) ");
177         } else {
178             try {
179                 dispatcher.cleanup();
180             } finally {
181                 ActionContext.setContext(null);
182             }
183         }
184     }
185 
186     /***
187      * Check whether the request matches a list of exclude patterns.
188      *
189      * @param request          The request to check patterns against
190      * @param excludedPatterns list of patterns for exclusion
191      *
192      * @return <tt>true</tt> if the request URI matches one of the given patterns
193      */
194     public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns ) {
195         if (excludedPatterns != null) {
196             String uri = getUri(request);
197             for ( Pattern pattern : excludedPatterns ) {
198                 if (pattern.matcher(uri).matches()) {
199                     return true;
200                 }
201             }
202         }
203         return false;
204     }
205 
206     /***
207      * Gets the uri from the request
208      *
209      * @param request The request
210      *
211      * @return The uri
212      */
213     private String getUri( HttpServletRequest request ) {
214         // handle http dispatcher includes.
215         String uri = (String) request.getAttribute("javax.servlet.include.servlet_path");
216         if (uri != null) {
217             return uri;
218         }
219 
220         uri = RequestUtils.getServletPath(request);
221         if (uri != null && !"".equals(uri)) {
222             return uri;
223         }
224 
225         uri = request.getRequestURI();
226         return uri.substring(request.getContextPath().length());
227     }
228 
229 }