1 /*
2 * $Id$
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.struts.extras.actions;
22
23 import jakarta.servlet.ServletException;
24 import jakarta.servlet.http.HttpServletRequest;
25 import jakarta.servlet.http.HttpServletResponse;
26
27 import org.apache.struts.action.ActionForm;
28 import org.apache.struts.action.ActionForward;
29 import org.apache.struts.action.ActionMapping;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34 * <p>An abstract <strong>Action</strong> that dispatches to a public method
35 * that is named by the <code>parameter</code> attribute of the corresponding
36 * ActionMapping. This is useful for developers who prefer to combine many
37 * related actions into a single Action class.</p>
38 *
39 * <p>To configure the use of this action in your <code>struts-config.xml</code>
40 * file, create an entry like this:</p>
41 *
42 * <pre><code>
43 * <action path="/saveSubscription"
44 * type="org.example.SubscriptionAction"
45 * name="subscriptionForm"
46 * scope="request"
47 * input="/subscription.jsp"
48 * parameter="method"/>
49 * </code></pre>
50 *
51 * <p>where 'method' is the name of a method in your subclass of
52 * MappingDispatchAction that has the same signature (other than method name)
53 * of the standard Action.execute method. For example, you might combine the
54 * methods for managing a subscription into a single MappingDispatchAction
55 * class using the following methods:</p>
56 *
57 * <ul>
58 *
59 * <li>public ActionForward create(ActionMapping mapping, ActionForm form,
60 * HttpServletRequest request, HttpServletResponse response) throws
61 * Exception</li>
62 *
63 * <li>public ActionForward edit(ActionMapping mapping, ActionForm form,
64 * HttpServletRequest request, HttpServletResponse response) throws
65 * Exception</li>
66 *
67 * <li>public ActionForward save(ActionMapping mapping, ActionForm form,
68 * HttpServletRequest request, HttpServletResponse response) throws
69 * Exception</li>
70 *
71 * <li>public ActionForward delete(ActionMapping mapping, ActionForm form,
72 * HttpServletRequest request, HttpServletResponse response) throws
73 * Exception</li>
74 *
75 * <li>public ActionForward list(ActionMapping mapping, ActionForm form,
76 * HttpServletRequest request, HttpServletResponse response) throws
77 * Exception</li>
78 *
79 * </ul>
80 *
81 * <p>for which you would create corresponding <action> configurations
82 * that reference this class:</p>
83 *
84 * <pre><code>
85 * <action path="/createSubscription"
86 * type="org.example.SubscriptionAction"
87 * parameter="create">
88 * <forward name="success" path="/editSubscription.jsp"/>
89 * </action>
90 *
91 * <action path="/editSubscription"
92 * type="org.example.SubscriptionAction"
93 * parameter="edit">
94 * <forward name="success" path="/editSubscription.jsp"/>
95 * </action>
96 *
97 * <action path="/saveSubscription"
98 * type="org.example.SubscriptionAction"
99 * parameter="save"
100 * name="subscriptionForm"
101 * validate="true"
102 * input="/editSubscription.jsp"
103 * scope="request">
104 * <forward name="success" path="/savedSubscription.jsp"/>
105 * </action>
106 *
107 * <action path="/deleteSubscription"
108 * type="org.example.SubscriptionAction"
109 * name="subscriptionForm"
110 * scope="request"
111 * input="/subscription.jsp"
112 * parameter="delete">
113 * <forward name="success" path="/deletedSubscription.jsp"/>
114 * </action>
115 *
116 * <action path="/listSubscriptions"
117 * type="org.example.SubscriptionAction"
118 * parameter="list">
119 * <forward name="success" path="/subscriptionList.jsp"/>
120 * </action>
121 * </code></pre>
122 *
123 * <p><strong>NOTE</strong> - Unlike DispatchAction, mapping characteristics
124 * may differ between the various handlers, so you can combine actions in the
125 * same class that, for example, differ in their use of forms or validation.
126 * Also, a request parameter, which would be visible to the application user,
127 * is not required to enable selection of the handler method. </p>
128 *
129 * @version $Rev$ $Date$
130 * @since Struts 1.2
131 */
132 public class MappingDispatchAction extends DispatchAction {
133 private static final long serialVersionUID = 8605425680931524975L;
134
135 // -------------------------------------------------------- Class Variables
136
137 /**
138 * The {@code Log} instance for this class.
139 */
140 private transient final Logger log =
141 LoggerFactory.getLogger(MappingDispatchAction.class);
142
143 // --------------------------------------------------------- Public Methods
144
145 /**
146 * Process the specified HTTP request, and create the corresponding HTTP
147 * response (or forward to another web component that will create it).
148 * Return an <code>ActionForward</code> instance describing where and how
149 * control should be forwarded, or <code>null</code> if the response has
150 * already been completed.
151 *
152 * This method dispatches the request to other methods of
153 * <code>MappingDispatchAction</code> using the 'parameter' attribute of
154 * <code>ActionMapping</code> and Java Introspection.
155 *
156 * @param mapping The ActionMapping used to select this instance
157 * @param form The optional ActionForm bean for this request (if any)
158 * @param request The HTTP request we are processing
159 * @param response The HTTP response we are creating
160 * @return Return an <code>ActionForward</code> instance describing where
161 * and how control should be forwarded, or <code>null</code> if
162 * the response has already been completed.
163 * @throws Exception if an exception occurs
164 */
165 public ActionForward execute(ActionMapping mapping, ActionForm form,
166 HttpServletRequest request, HttpServletResponse response)
167 throws Exception {
168 // Use the overridden getMethodName.
169 return super.execute(mapping, form, request, response);
170 }
171
172 /**
173 * Method which is dispatched to when there is no value for the parameter
174 * in the ActionMapping. Subclasses of <code>MappingDispatchAction</code>
175 * should override this method if they wish to provide default behavior
176 * different than throwing a ServletException.
177 *
178 * @param mapping The ActionMapping used to select this instance
179 * @param form The optional ActionForm bean for this request (if any)
180 * @param request The HTTP request we are processing
181 * @param response The HTTP response we are creating
182 * @return Return an <code>ActionForward</code> instance describing where
183 * and how control should be forwarded, or <code>null</code> if
184 * the response has already been completed.
185 * @throws Exception if an exception occurs
186 */
187 protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
188 HttpServletRequest request, HttpServletResponse response)
189 throws Exception {
190 String message =
191 messages.getMessage("mapping.parameter", mapping.getPath());
192
193 log.error(message);
194
195 throw new ServletException(message);
196 }
197
198 /**
199 * <p>Returns the parameter value.</p>
200 *
201 * @param mapping The ActionMapping used to select this instance
202 * @param form The optional ActionForm bean for this request (if any)
203 * @param request The HTTP request we are processing
204 * @param response The HTTP response we are creating
205 * @return The <code>ActionMapping</code> parameter's value
206 */
207 protected String getParameter(ActionMapping mapping, ActionForm form,
208 HttpServletRequest request, HttpServletResponse response)
209 throws Exception {
210
211 return mapping.getParameter();
212
213 }
214
215 /**
216 * Returns the method name, given a parameter's value.
217 *
218 * @param mapping The ActionMapping used to select this instance
219 * @param form The optional ActionForm bean for this request (if
220 * any)
221 * @param request The HTTP request we are processing
222 * @param response The HTTP response we are creating
223 * @param parameter The <code>ActionMapping</code> parameter's name
224 * @return The method's name.
225 * @throws Exception if an error occurs
226 * @since Struts 1.2.0
227 */
228 protected String getMethodName(ActionMapping mapping, ActionForm form,
229 HttpServletRequest request, HttpServletResponse response,
230 String parameter) throws Exception {
231 // Return the unresolved mapping parameter.
232 return parameter;
233 }
234 }