View Javadoc

1   /*
2    * $Id: ServletDispatcherResult.java 658883 2008-05-21 21:31:04Z musachy $
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  
22  package org.apache.struts2.dispatcher;
23  
24  import java.util.Map;
25  
26  import javax.servlet.RequestDispatcher;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  import javax.servlet.jsp.PageContext;
30  
31  import org.apache.struts2.ServletActionContext;
32  import org.apache.struts2.views.util.UrlHelper;
33  
34  import com.opensymphony.xwork2.ActionInvocation;
35  import com.opensymphony.xwork2.util.logging.Logger;
36  import com.opensymphony.xwork2.util.logging.LoggerFactory;
37  
38  
39  /***
40   * <!-- START SNIPPET: description -->
41   *
42   * Includes or forwards to a view (usually a jsp). Behind the scenes Struts
43   * will use a RequestDispatcher, where the target servlet/JSP receives the same
44   * request/response objects as the original servlet/JSP. Therefore, you can pass
45   * data between them using request.setAttribute() - the Struts action is
46   * available.
47   * <p/>
48   * There are three possible ways the result can be executed:
49   *
50   * <ul>
51   *
52   * <li>If we are in the scope of a JSP (a PageContext is available), PageContext's
53   * {@link PageContext#include(String) include} method is called.</li>
54   *
55   * <li>If there is no PageContext and we're not in any sort of include (there is no
56   * "javax.servlet.include.servlet_path" in the request attributes), then a call to
57   * {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse) forward}
58   * is made.</li>
59   *
60   * <li>Otherwise, {@link RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse) include}
61   * is called.</li>
62   *
63   * </ul>
64   * <!-- END SNIPPET: description -->
65   *
66   * <b>This result type takes the following parameters:</b>
67   *
68   * <!-- START SNIPPET: params -->
69   *
70   * <ul>
71   *
72   * <li><b>location (default)</b> - the location to go to after execution (ex. jsp).</li>
73   *
74   * <li><b>parse</b> - true by default. If set to false, the location param will not be parsed for Ognl expressions.</li>
75   *
76   * </ul>
77   *
78   * <!-- END SNIPPET: params -->
79   *
80   * <b>Example:</b>
81   *
82   * <pre><!-- START SNIPPET: example -->
83   * &lt;result name="success" type="dispatcher"&gt;
84   *   &lt;param name="location"&gt;foo.jsp&lt;/param&gt;
85   * &lt;/result&gt;
86   * <!-- END SNIPPET: example --></pre>
87   *
88   * This result follows the same rules from {@link StrutsResultSupport}.
89   *
90   * @see javax.servlet.RequestDispatcher
91   */
92  public class ServletDispatcherResult extends StrutsResultSupport {
93  
94      private static final long serialVersionUID = -1970659272360685627L;
95  
96      private static final Logger LOG = LoggerFactory.getLogger(ServletDispatcherResult.class);
97  
98      public ServletDispatcherResult() {
99          super();
100     }
101 
102     public ServletDispatcherResult(String location) {
103         super(location);
104     }
105 
106     /***
107      * Dispatches to the given location. Does its forward via a RequestDispatcher. If the
108      * dispatch fails a 404 error will be sent back in the http response.
109      *
110      * @param finalLocation the location to dispatch to.
111      * @param invocation    the execution state of the action
112      * @throws Exception if an error occurs. If the dispatch fails the error will go back via the
113      *                   HTTP request.
114      */
115     public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
116         if (LOG.isDebugEnabled()) {
117             LOG.debug("Forwarding to location " + finalLocation);
118         }
119 
120         PageContext pageContext = ServletActionContext.getPageContext();
121 
122         if (pageContext != null) {
123             pageContext.include(finalLocation);
124         } else {
125             HttpServletRequest request = ServletActionContext.getRequest();
126             HttpServletResponse response = ServletActionContext.getResponse();
127             RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
128 
129             //add parameters passed on the location to #parameters
130             // see WW-2120
131             if (invocation != null && finalLocation != null && finalLocation.length() > 0
132                     && finalLocation.indexOf("?") > 0) {
133                 String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
134                 Map parameters = (Map) invocation.getInvocationContext().getContextMap().get("parameters");
135                 Map queryParams = UrlHelper.parseQueryString(queryString, true);
136                 if (queryParams != null && !queryParams.isEmpty())
137                     parameters.putAll(queryParams);
138             }
139 
140             // if the view doesn't exist, let's do a 404
141             if (dispatcher == null) {
142                 response.sendError(404, "result '" + finalLocation + "' not found");
143 
144                 return;
145             }
146 
147             // If we're included, then include the view
148             // Otherwise do forward
149             // This allow the page to, for example, set content type
150             if (!response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
151                 request.setAttribute("struts.view_uri", finalLocation);
152                 request.setAttribute("struts.request_uri", request.getRequestURI());
153 
154                 dispatcher.forward(request, response);
155             } else {
156                 dispatcher.include(request, response);
157             }
158         }
159     }
160 }