View Javadoc

1   /*
2    * $Id: ServletRedirectResult.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  
22  package org.apache.struts2.dispatcher;
23  
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  import static javax.servlet.http.HttpServletResponse.*;
27  
28  import org.apache.struts2.ServletActionContext;
29  import org.apache.struts2.dispatcher.mapper.ActionMapper;
30  import org.apache.struts2.dispatcher.mapper.ActionMapping;
31  
32  import com.opensymphony.xwork2.ActionContext;
33  import com.opensymphony.xwork2.ActionInvocation;
34  import com.opensymphony.xwork2.inject.Inject;
35  import com.opensymphony.xwork2.util.logging.Logger;
36  import com.opensymphony.xwork2.util.logging.LoggerFactory;
37  
38  import java.io.IOException;
39  
40  
41  /***
42   * <!-- START SNIPPET: description -->
43   *
44   * Calls the {@link HttpServletResponse#sendRedirect(String) sendRedirect}
45   * method to the location specified. The response is told to redirect the
46   * browser to the specified location (a new request from the client). The
47   * consequence of doing this means that the action (action instance, action
48   * errors, field errors, etc) that was just executed is lost and no longer
49   * available. This is because actions are built on a single-thread model. The
50   * only way to pass data is through the session or with web parameters
51   * (url?name=value) which can be OGNL expressions.
52   *
53   * <!-- END SNIPPET: description -->
54   * <p/>
55   * <b>This result type takes the following parameters:</b>
56   *
57   * <!-- START SNIPPET: params -->
58   *
59   * <ul>
60   *
61   * <li><b>location (default)</b> - the location to go to after execution.</li>
62   *
63   * <li><b>parse</b> - true by default. If set to false, the location param will
64   * not be parsed for Ognl expressions.</li>
65   *
66   * </ul>
67   *
68   * <p>
69   * This result follows the same rules from {@link StrutsResultSupport}.
70   * </p>
71   *
72   * <!-- END SNIPPET: params -->
73   *
74   * <b>Example:</b>
75   *
76   * <pre><!-- START SNIPPET: example -->
77   * &lt;result name="success" type="redirect"&gt;
78   *   &lt;param name="location"&gt;foo.jsp&lt;/param&gt;
79   *   &lt;param name="parse"&gt;false&lt;/param&gt;
80   * &lt;/result&gt;
81   * <!-- END SNIPPET: example --></pre>
82   *
83   */
84  public class ServletRedirectResult extends StrutsResultSupport {
85  
86      private static final long serialVersionUID = 6316947346435301270L;
87  
88      private static final Logger LOG = LoggerFactory.getLogger(ServletRedirectResult.class);
89  
90      protected boolean prependServletContext = true;
91  
92      protected ActionMapper actionMapper;
93  
94      protected int statusCode = SC_FOUND;
95  
96      public ServletRedirectResult() {
97          super();
98      }
99  
100     public ServletRedirectResult(String location) {
101         super(location);
102     }
103     
104     @Inject
105     public void setActionMapper(ActionMapper mapper) {
106         this.actionMapper = mapper;
107     }
108 
109     public void setStatusCode(int code) {
110         this.statusCode = code;
111     }
112 
113     /***
114      * Sets whether or not to prepend the servlet context path to the redirected URL.
115      *
116      * @param prependServletContext <tt>true</tt> to prepend the location with the servlet context path,
117      *                              <tt>false</tt> otherwise.
118      */
119     public void setPrependServletContext(boolean prependServletContext) {
120         this.prependServletContext = prependServletContext;
121     }
122 
123     /***
124      * Redirects to the location specified by calling {@link HttpServletResponse#sendRedirect(String)}.
125      *
126      * @param finalLocation the location to redirect to.
127      * @param invocation    an encapsulation of the action execution state.
128      * @throws Exception if an error occurs when redirecting.
129      */
130     protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
131         ActionContext ctx = invocation.getInvocationContext();
132         HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
133         HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);
134 
135         if (isPathUrl(finalLocation)) {
136             if (!finalLocation.startsWith("/")) {
137                 ActionMapping mapping = actionMapper.getMapping(
138                         request, Dispatcher.getInstance().getConfigurationManager()); 
139                 String namespace = null;
140                 if (mapping != null) {
141                     namespace = mapping.getNamespace();
142                 }
143 
144                 if ((namespace != null) && (namespace.length() > 0) && (!"/".equals(namespace))) {
145                     finalLocation = namespace + "/" + finalLocation;
146                 } else {
147                     finalLocation = "/" + finalLocation;
148                 }
149             }
150 
151             // if the URL's are relative to the servlet context, append the servlet context path
152             if (prependServletContext && (request.getContextPath() != null) && (request.getContextPath().length() > 0)) {
153                 finalLocation = request.getContextPath() + finalLocation;
154             }
155 
156             finalLocation = response.encodeRedirectURL(finalLocation);
157         }
158 
159         if (LOG.isDebugEnabled()) {
160             LOG.debug("Redirecting to finalLocation " + finalLocation);
161         }
162 
163         sendRedirect(response, finalLocation);
164     }
165 
166     /***
167      * Sends the redirection.  Can be overridden to customize how the redirect is handled (i.e. to use a different
168      * status code)
169      *
170      * @param response The response
171      * @param finalLocation The location URI
172      * @throws IOException
173      */
174     protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException {
175         if (SC_FOUND == statusCode) {
176             response.sendRedirect(finalLocation);
177         } else {
178             response.setStatus(statusCode);
179             response.setHeader("Location", finalLocation);
180             response.getWriter().write(finalLocation);
181             response.getWriter().close();
182         }
183 
184     }
185 
186     private static boolean isPathUrl(String url) {
187         // filter out "http:", "https:", "mailto:", "file:", "ftp:"
188         // since the only valid places for : in URL's is before the path specification
189         // either before the port, or after the protocol
190         return (url.indexOf(':') == -1);
191     }
192 }