1 package org.apache.struts.apps.mailreader.actions;
2
3 import org.apache.commons.beanutils.PropertyUtils;
4 import org.apache.struts.action.ActionForm;
5 import org.apache.struts.action.ActionForward;
6 import org.apache.struts.action.ActionMapping;
7 import org.apache.struts.action.ActionMessage;
8 import org.apache.struts.action.ActionMessages;
9 import org.apache.struts.action.DynaActionForm;
10 import org.apache.struts.apps.mailreader.Constants;
11 import org.apache.struts.apps.mailreader.dao.ExpiredPasswordException;
12 import org.apache.struts.apps.mailreader.dao.User;
13 import org.apache.struts.apps.mailreader.dao.UserDatabase;
14
15 import javax.servlet.ServletException;
16 import javax.servlet.http.HttpServletRequest;
17 import javax.servlet.http.HttpServletResponse;
18 import javax.servlet.http.HttpSession;
19 import java.lang.reflect.InvocationTargetException;
20
21 /***
22 * <p>
23 * Provide an Edit method for retrieving an existing user,
24 * and a Save method for updating or inserting a user.
25 * </p><p>
26 * Both methods utilize a RegistrationForm to obtain or expose User details.
27 * If Save is used to create a user,
28 * additional validations ensure input is nominal.
29 * When a user is created,
30 * Save also handles the initial logon.
31 * </p>
32 */
33 public final class RegistrationAction extends BaseAction {
34
35
36
37 /***
38 * <p>
39 * Name of fromAddress field ["fromAddress"].
40 * </p>
41 */
42 public final static String FROM_ADDRESS = "fromAddress";
43
44 /***
45 * <p>
46 * Name of fullName field ["fullName"].
47 * </p>
48 */
49 public final static String FULL_NAME = "fullName";
50
51 /***
52 * <p>
53 * Name of password confirmation field ["password2"].
54 * </p>
55 */
56 public final static String PASSWORD2 = "password2";
57
58 /***
59 * <p>
60 * Name of replyToAddress field ["replyToAddress"].
61 * </p>
62 */
63 public final static String REPLY_TO_ADDRESS = "replyToAddress";
64
65
66
67 /***
68 * <p>
69 * The message prefix to use when populating a Registration Form.
70 * </p>
71 */
72 final String LOG_REGISTRATION_POPULATE = "RegistrationForm.populate";
73
74 /***
75 * <p>
76 * Helper method to post error message when user already exists.
77 * </p>
78 *
79 * @param username Existing username
80 * @param errors Our ActionMessages collection
81 */
82 private void errorUsernameUnique(String username,
83 ActionMessages errors) {
84 errors.add(
85 USERNAME,
86 new org.apache.struts.action.ActionMessage(
87 "error.username.unique", username));
88 }
89
90 /***
91 * <p>
92 * Verify input for creating a new user,
93 * create the user, and process the login.
94 * </p>
95 *
96 * @param form The input form
97 * @param request The HttpRequest being served
98 * @param errors The ActionMessages collection for any errors
99 * @return A new User and empty Errors if create succeeds,
100 * or null and Errors if create fails
101 */
102 private User doCreateUser(
103 ActionForm form,
104 HttpServletRequest request,
105 ActionMessages errors) {
106
107 if (log.isTraceEnabled()) {
108 log.trace(" Perform additional validations on Create");
109 }
110
111 UserDatabase database = doGetUserDatabase();
112 String username = doGet(form, USERNAME);
113 try {
114 if (database.findUser(username) != null) {
115 errorUsernameUnique(username, errors);
116 }
117 }
118 catch (ExpiredPasswordException e) {
119 errorUsernameUnique(username, errors);
120 errors.add("errors.literal", new ActionMessage(e.getMessage()));
121 }
122
123 String password = doGet(form, PASSWORD);
124 if ((password == null) || (password.length() < 1)) {
125 errors.add(PASSWORD, new ActionMessage("error.password.required"));
126
127 String password2 = doGet(form, PASSWORD2);
128 if ((password2 == null) || (password2.length() < 1)) {
129 errors.add(
130 PASSWORD2,
131 new ActionMessage("error.password2.required"));
132 }
133 }
134
135 if (!errors.isEmpty()) {
136 return null;
137 }
138
139 User user = database.createUser(username);
140
141
142 HttpSession session = request.getSession();
143 session.setAttribute(Constants.USER_KEY, user);
144 if (log.isTraceEnabled()) {
145 log.trace(
146 " User: '"
147 + user.getUsername()
148 + "' logged on in session: "
149 + session.getId());
150 }
151
152 return user;
153 }
154
155 /***
156 * <p>
157 * Helper method to populate the input form from the User object.
158 * </p>
159 *
160 * @param form Form with incoming values
161 * @param user User object to populate
162 * @throws ServletException On any error
163 */
164 private void doPopulate(ActionForm form, User user)
165 throws ServletException {
166
167 final String title = Constants.EDIT;
168
169 if (log.isTraceEnabled()) {
170 log.trace(Constants.LOG_POPULATE_FORM + user);
171 }
172
173 try {
174 PropertyUtils.copyProperties(form, user);
175 DynaActionForm dyna = (DynaActionForm) form;
176 dyna.set(TASK, title);
177 dyna.set(PASSWORD, null);
178 dyna.set(PASSWORD2, null);
179 } catch (InvocationTargetException e) {
180 Throwable t = e.getTargetException();
181 if (t == null) {
182 t = e;
183 }
184 log.error(LOG_REGISTRATION_POPULATE, t);
185 throw new ServletException(LOG_REGISTRATION_POPULATE, t);
186 } catch (Throwable t) {
187 log.error(LOG_REGISTRATION_POPULATE, t);
188 throw new ServletException(LOG_REGISTRATION_POPULATE, t);
189 }
190 }
191
192 /***
193 * <p>
194 * Helper method to populate the User object from the input form.
195 * </p>
196 *
197 * @param user User object to populate
198 * @param form Form with incoming values
199 * @throws ServletException On any error
200 */
201 private void doPopulate(User user, ActionForm form)
202 throws ServletException {
203
204 if (log.isTraceEnabled()) {
205 log.trace(Constants.LOG_POPULATE_USER + user);
206 }
207
208 try {
209 String oldPassword = user.getPassword();
210 PropertyUtils.copyProperties(user, form);
211 String password = doGet(form, PASSWORD);
212 if ((password == null)
213 || (password.length() < 1)) {
214
215 user.setPassword(oldPassword);
216 }
217
218 } catch (InvocationTargetException e) {
219 Throwable t = e.getTargetException();
220 if (t == null) {
221 t = e;
222 }
223
224 log.error(LOG_REGISTRATION_POPULATE, t);
225 throw new ServletException(LOG_REGISTRATION_POPULATE, t);
226
227 } catch (Throwable t) {
228 log.error(LOG_REGISTRATION_POPULATE, t);
229 throw new ServletException(LOG_REGISTRATION_POPULATE, t);
230 }
231 }
232
233 /***
234 * <p>
235 * Validate and clear the transactional token,
236 * creating logging statements as needed.
237 * </p>
238 *
239 * @param request Our HttpServletRequest
240 * @param errors ActionErrors to transfer any messages
241 */
242 private void doValidateToken(HttpServletRequest request,
243 ActionMessages errors) {
244
245 if (log.isTraceEnabled()) {
246 log.trace(Constants.LOG_TOKEN_CHECK);
247 }
248
249 if (!isTokenValid(request)) {
250 errors.add(
251 ActionMessages.GLOBAL_MESSAGE,
252 new ActionMessage(Constants.MSG_TRANSACTION_TOKEN));
253 }
254
255 resetToken(request);
256 }
257
258
259
260 /***
261 * <p>
262 * Retrieve the User object to edit or null if the User does not exist,
263 * and set an transactional token to later detect multiple Save commands.
264 * </p>
265 *
266 * @param mapping Our ActionMapping
267 * @param form Our ActionForm
268 * @param request Our HttpServletRequest
269 * @param response Our HttpServletResponse
270 * @return The "Success" result for this mapping
271 * @throws Exception on any error
272 */
273 public ActionForward Edit(
274 ActionMapping mapping,
275 ActionForm form,
276 HttpServletRequest request,
277 HttpServletResponse response)
278 throws Exception {
279
280 final String method = Constants.EDIT;
281 doLogProcess(mapping, method);
282
283 HttpSession session = request.getSession();
284 User user = doGetUser(session);
285 boolean updating = (user != null);
286 if (updating) {
287 doPopulate(form, user);
288 }
289
290 doSaveToken(request);
291 return doFindSuccess(mapping);
292 }
293
294 /***
295 * <p>
296 * Insert or update a User object to the persistent store.
297 * </p><p>
298 * If a User is not logged in,
299 * then a new User is created and automatically logged in.
300 * Otherwise, the existing User is updated.
301 * </p>
302 *
303 * @param mapping Our ActionMapping
304 * @param form Our ActionForm
305 * @param request Our HttpServletRequest
306 * @param response Our HttpServletResponse
307 * @return The "Success" result for this mapping
308 * @throws Exception on any error
309 */
310 public ActionForward Save(
311 ActionMapping mapping,
312 ActionForm form,
313 HttpServletRequest request,
314 HttpServletResponse response)
315 throws Exception {
316
317 final String method = Constants.SAVE;
318 doLogProcess(mapping, method);
319
320 HttpSession session = request.getSession();
321 if (isCancelled(request)) {
322 doCancel(session, method, Constants.SUBSCRIPTION_KEY);
323 return doFindSuccess(mapping);
324 }
325
326 ActionMessages errors = new ActionMessages();
327 doValidateToken(request, errors);
328
329 if (!errors.isEmpty()) {
330 return doInputForward(mapping, request, errors);
331 }
332
333 User user = doGetUser(session);
334 if (user == null) {
335 user = doCreateUser(form, request, errors);
336 if (!errors.isEmpty()) {
337 return doInputForward(mapping, request, errors);
338 }
339 }
340
341 doPopulate(user, form);
342 doSaveUser(user);
343
344 return doFindSuccess(mapping);
345 }
346
347 }