View Javadoc

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      // --- Public Constants --
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      // ---- Private Methods ----
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         // Log the user in
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     // ----- Public Methods ----
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 }