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.chain.commands;
22
23 import java.util.Map;
24
25 import org.apache.struts.Globals;
26 import org.apache.struts.action.ActionForm;
27 import org.apache.struts.chain.contexts.ActionContext;
28 import org.apache.struts.config.ActionConfig;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33 * <p>Populate the form bean (if any) for this request.</p>
34 *
35 * @version $Rev$ $Date: 2005-11-12 13:01:44 -0500 (Sat, 12 Nov 2005)
36 * $
37 */
38 public abstract class AbstractPopulateActionForm extends ActionCommandBase {
39
40 /**
41 * The {@code Log} instance for this class.
42 */
43 private final Logger log =
44 LoggerFactory.getLogger(AbstractPopulateActionForm.class);
45
46 // ---------------------------------------------------------- Public Methods
47
48 /**
49 * <p>Populate the form bean (if any) for this request.</p>
50 *
51 * @param actionCtx The <code>Context</code> for the current request
52 * @return <code>false</code> so that processing continues
53 * @throws Exception On an unexpected error
54 */
55 @Override
56 protected boolean execute_(ActionContext actionCtx)
57 throws Exception {
58
59 ActionConfig actionConfig = actionCtx.getActionConfig();
60 ActionForm actionForm = actionCtx.getActionForm();
61
62 // First determine if the request was cancelled
63 handleCancel(actionCtx, actionConfig, actionForm);
64
65 // Is there a form bean for this request?
66 if (actionForm == null) {
67 return (false);
68 }
69
70 // Reset the form bean only if configured so
71 if (isReset(actionCtx, actionConfig)) {
72 log.debug("Reseting form bean '{}'", actionConfig.getName());
73 reset(actionCtx, actionConfig, actionForm);
74 }
75
76 // Populate the form bean only if configured so
77 if (isPopulate(actionCtx, actionConfig)) {
78 log.debug("Populating form bean '{}'", actionConfig.getName());
79 populate(actionCtx, actionConfig, actionForm);
80 }
81
82 return CONTINUE_PROCESSING;
83 }
84
85 // ------------------------------------------------------- Protected Methods
86
87 /**
88 * Determines whether an action form should be reset
89 *
90 * @param context the ActionContext we are processing
91 * @param actionConfig action config for current request
92 *
93 * @return true if action form should be reset
94 *
95 * @since Struts 1.4
96 */
97 protected abstract boolean isReset(ActionContext context,
98 ActionConfig actionConfig);
99
100 /**
101 * Determines whether an action form should be populated.
102 *
103 * @param context the ActionContext we are processing
104 * @param actionConfig action config for current request
105 * @return true if action form should be populated
106 * @since Struts 1.4
107 */
108 protected abstract boolean isPopulate(ActionContext context,
109 ActionConfig actionConfig);
110
111 /**
112 * <p>Call the <code>reset()</code> method on the specified form
113 * bean.</p>
114 *
115 * @param context The context for this request
116 * @param actionConfig The actionConfig for this request
117 * @param actionForm The form bean for this request
118 */
119 protected abstract void reset(ActionContext context,
120 ActionConfig actionConfig, ActionForm actionForm);
121
122 /**
123 * <p> Populate the given <code>ActionForm</code> with request parameter
124 * values, taking into account any prefix/suffix values configured on the
125 * given <code>ActionConfig</code>. </p>
126 *
127 * @param context The ActionContext we are processing
128 * @param actionConfig The ActionConfig we are processing
129 * @param actionForm The ActionForm we are processing
130 * @throws Exception On an unexpected error
131 */
132 protected abstract void populate(ActionContext context,
133 ActionConfig actionConfig, ActionForm actionForm)
134 throws Exception;
135
136 // original implementation casting context to WebContext is not safe
137 // when the input value is an ActionContext.
138
139 /**
140 * <p>For a given request parameter name, trim off any prefix and/or
141 * suffix which are defined in <code>actionConfig</code> and return what
142 * remains. If either prefix or suffix is defined, then return null for
143 * <code>name</code> values which do not begin or end accordingly.</p>
144 *
145 * @param actionConfig The ActionConfig we are processing
146 * @param name The request parameter name to proceess
147 * @return The request parameter name trimmed of any suffix or prefix
148 */
149 protected String trimParameterName(ActionConfig actionConfig, String name) {
150 String stripped = name;
151 String prefix = actionConfig.getPrefix();
152 String suffix = actionConfig.getSuffix();
153
154 if (prefix != null) {
155 if (!stripped.startsWith(prefix)) {
156 return null;
157 }
158
159 stripped = stripped.substring(prefix.length());
160 }
161
162 if (suffix != null) {
163 if (!stripped.endsWith(suffix)) {
164 return null;
165 }
166
167 stripped =
168 stripped.substring(0, stripped.length() - suffix.length());
169 }
170
171 return stripped;
172 }
173
174 /**
175 * <p>Take into account whether the request includes any defined value for
176 * the global "cancel" parameter.</p> <p> An issue was raised (but I don't
177 * think a Bugzilla ticket created) about the security implications of
178 * using a well-known cancel property which skips form validation, as you
179 * may not write your actions to deal with the cancellation case. </p>
180 *
181 * @param context The ActionContext we are processing
182 * @param actionConfig The ActionConfig we are processing
183 * @param actionForm The ActionForm we are processing
184 * @throws Exception On an unexpected error
185 * @see Globals#CANCEL_PROPERTY
186 * @see Globals#CANCEL_PROPERTY_X
187 */
188 protected void handleCancel(ActionContext context,
189 ActionConfig actionConfig, ActionForm actionForm)
190 throws Exception {
191 Map<String, String[]> paramValues = context.getParameterMap();
192
193 // Set the cancellation attribute if appropriate
194 if ((paramValues.get(Globals.CANCEL_PROPERTY) != null)
195 || (paramValues.get(Globals.CANCEL_PROPERTY_X) != null)) {
196 context.setCancelled(Boolean.TRUE);
197 } else {
198 context.setCancelled(Boolean.FALSE);
199 }
200 }
201 }