1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.portlet.result;
23
24 import java.util.Arrays;
25 import java.util.Iterator;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.portlet.PortletMode;
31
32 import org.apache.struts2.dispatcher.ServletActionRedirectResult;
33 import org.apache.struts2.dispatcher.mapper.ActionMapper;
34 import org.apache.struts2.dispatcher.mapper.ActionMapping;
35 import org.apache.struts2.portlet.PortletActionConstants;
36 import org.apache.struts2.views.util.UrlHelper;
37
38 import com.opensymphony.xwork2.ActionInvocation;
39 import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
40 import com.opensymphony.xwork2.util.reflection.ReflectionException;
41 import com.opensymphony.xwork2.util.logging.Logger;
42 import com.opensymphony.xwork2.util.logging.LoggerFactory;
43 import com.opensymphony.xwork2.config.entities.ResultConfig;
44 import com.opensymphony.xwork2.inject.Inject;
45
46 /***
47 *
48 * Portlet modification of the {@link ServletActionRedirectResult}.
49 *
50 * <!-- START SNIPPET: description -->
51 *
52 * This result uses the {@link ActionMapper} provided by the
53 * {@link ActionMapperFactory} to instruct the render phase to invoke the
54 * specified action and (optional) namespace. This is better than the
55 * {@link PortletResult} because it does not require you to encode the URL
56 * patterns processed by the {@link ActionMapper} in to your struts.xml
57 * configuration files. This means you can change your URL patterns at any point
58 * and your application will still work. It is strongly recommended that if you
59 * are redirecting to another action, you use this result rather than the
60 * standard redirect result.
61 *
62 * See examples below for an example of how request parameters could be passed
63 * in.
64 *
65 * <!-- END SNIPPET: description -->
66 *
67 * <b>This result type takes the following parameters:</b>
68 *
69 * <!-- START SNIPPET: params -->
70 *
71 * <ul>
72 *
73 * <li><b>actionName (default)</b> - the name of the action that will be
74 * redirect to</li>
75 *
76 * <li><b>namespace</b> - used to determine which namespace the action is in
77 * that we're redirecting to . If namespace is null, this defaults to the
78 * current namespace</li>
79 *
80 * </ul>
81 *
82 * <!-- END SNIPPET: params -->
83 *
84 * <b>Example:</b>
85 *
86 * <pre>
87 * <!-- START SNIPPET: example -->
88 * <package name="public" extends="struts-default">
89 * <action name="login" class="...">
90 * <!-- Redirect to another namespace -->
91 * <result type="redirectAction">
92 * <param name="actionName">dashboard</param>
93 * <param name="namespace">/secure</param>
94 * </result>
95 * </action>
96 * </package>
97 *
98 * <package name="secure" extends="struts-default" namespace="/secure">
99 * <-- Redirect to an action in the same namespace -->
100 * <action name="dashboard" class="...">
101 * <result>dashboard.jsp</result>
102 * <result name="error" type="redirectAction">error</result>
103 * </action>
104 *
105 * <action name="error" class="...">
106 * <result>error.jsp</result>
107 * </action>
108 * </package>
109 *
110 * <package name="passingRequestParameters" extends="struts-default" namespace="/passingRequestParameters">
111 * <-- Pass parameters (reportType, width and height) -->
112 * <!--
113 * The redirectAction url generated will be :
114 * /genReport/generateReport.action?reportType=pie&width=100&height=100
115 * -->
116 * <action name="gatherReportInfo" class="...">
117 * <result name="showReportResult" type="redirectAction">
118 * <param name="actionName">generateReport</param>
119 * <param name="namespace">/genReport</param>
120 * <param name="reportType">pie</param>
121 * <param name="width">100</param>
122 * <param name="height">100</param>
123 * </result>
124 * </action>
125 * </package>
126 *
127 *
128 * <!-- END SNIPPET: example -->
129 * </pre>
130 *
131 * @see ActionMapper
132 */
133 public class PortletActionRedirectResult extends PortletResult implements ReflectionExceptionHandler {
134
135 private static final long serialVersionUID = -7627388936683562557L;
136
137 private static final Logger LOG = LoggerFactory.getLogger(PortletActionRedirectResult.class);
138
139 /*** The default parameter */
140 public static final String DEFAULT_PARAM = "actionName";
141
142 protected String actionName;
143
144 protected String namespace;
145
146 protected String method;
147
148 private Map<String, String> requestParameters = new LinkedHashMap<String, String>();
149
150 private ActionMapper actionMapper;
151
152 public PortletActionRedirectResult() {
153 super();
154 }
155
156 public PortletActionRedirectResult(String actionName) {
157 this(null, actionName, null);
158 }
159
160 public PortletActionRedirectResult(String actionName, String method) {
161 this(null, actionName, method);
162 }
163
164 public PortletActionRedirectResult(String namespace, String actionName, String method) {
165 super(null);
166 this.namespace = namespace;
167 this.actionName = actionName;
168 this.method = method;
169 }
170
171 protected List<String> prohibitedResultParam = Arrays.asList(new String[] { DEFAULT_PARAM, "namespace", "method",
172 "encode", "parse", "location", "prependServletContext" });
173
174 @Inject
175 public void setActionMapper(ActionMapper actionMapper) {
176 this.actionMapper = actionMapper;
177 }
178
179 /***
180 * @see com.opensymphony.xwork2.Result#execute(com.opensymphony.xwork2.ActionInvocation)
181 */
182 public void execute(ActionInvocation invocation) throws Exception {
183 actionName = conditionalParse(actionName, invocation);
184 if (portletMode != null) {
185 Map<PortletMode, String> namespaceMap = (Map<PortletMode, String>) invocation.getInvocationContext().get(
186 PortletActionConstants.MODE_NAMESPACE_MAP);
187 namespace = namespaceMap.get(portletMode);
188 }
189 if (namespace == null) {
190 namespace = invocation.getProxy().getNamespace();
191 } else {
192 namespace = conditionalParse(namespace, invocation);
193 }
194 if (method == null) {
195 method = "";
196 } else {
197 method = conditionalParse(method, invocation);
198 }
199
200 String resultCode = invocation.getResultCode();
201 if (resultCode != null) {
202 ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(resultCode);
203 Map resultConfigParams = resultConfig.getParams();
204 for (Iterator i = resultConfigParams.entrySet().iterator(); i.hasNext();) {
205 Map.Entry e = (Map.Entry) i.next();
206 if (!prohibitedResultParam.contains(e.getKey())) {
207 requestParameters.put(e.getKey().toString(), e.getValue() == null ? "" : conditionalParse(e
208 .getValue().toString(), invocation));
209 }
210 }
211 }
212
213 StringBuilder tmpLocation = new StringBuilder(actionMapper.getUriFromActionMapping(new ActionMapping(actionName,
214 namespace, method, null)));
215 UrlHelper.buildParametersString(requestParameters, tmpLocation, "&");
216
217 setLocation(tmpLocation.toString());
218
219 super.execute(invocation);
220 }
221
222 /***
223 * Sets the action name
224 *
225 * @param actionName
226 * The name
227 */
228 public void setActionName(String actionName) {
229 this.actionName = actionName;
230 }
231
232 /***
233 * Sets the namespace
234 *
235 * @param namespace
236 * The namespace
237 */
238 public void setNamespace(String namespace) {
239 this.namespace = namespace;
240 }
241
242 /***
243 * Sets the method
244 *
245 * @param method
246 * The method
247 */
248 public void setMethod(String method) {
249 this.method = method;
250 }
251
252 /***
253 * Adds a request parameter to be added to the redirect url
254 *
255 * @param key
256 * The parameter name
257 * @param value
258 * The parameter value
259 */
260 public PortletActionRedirectResult addParameter(String key, Object value) {
261 requestParameters.put(key, String.valueOf(value));
262 return this;
263 }
264
265 public void handle(ReflectionException ex) {
266
267 LOG.debug(ex.getMessage(), ex);
268 }
269 }