View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.portlets.registration;
18  
19  import java.io.FileNotFoundException;
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Date;
24  import java.util.HashMap;
25  import java.util.LinkedList;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.MissingResourceException;
30  import java.util.ResourceBundle;
31  
32  import javax.portlet.ActionRequest;
33  import javax.portlet.ActionResponse;
34  import javax.portlet.PortletConfig;
35  import javax.portlet.PortletException;
36  import javax.portlet.PortletMode;
37  import javax.portlet.PortletPreferences;
38  import javax.portlet.PortletRequest;
39  import javax.portlet.PortletResponse;
40  import javax.portlet.RenderRequest;
41  import javax.portlet.RenderResponse;
42  
43  import org.apache.jetspeed.CommonPortletServices;
44  import org.apache.jetspeed.PortalReservedParameters;
45  import org.apache.jetspeed.administration.AdministrationEmailException;
46  import org.apache.jetspeed.administration.PortalAdministration;
47  import org.apache.jetspeed.locator.JetspeedTemplateLocator;
48  import org.apache.jetspeed.locator.LocatorDescriptor;
49  import org.apache.jetspeed.locator.TemplateDescriptor;
50  import org.apache.jetspeed.locator.TemplateLocatorException;
51  import org.apache.jetspeed.request.RequestContext;
52  import org.apache.jetspeed.security.SecurityException;
53  import org.apache.jetspeed.security.User;
54  import org.apache.jetspeed.security.UserManager;
55  import org.apache.portals.bridges.util.PreferencesHelper;
56  import org.apache.portals.bridges.velocity.AbstractVelocityMessagingPortlet;
57  import org.apache.portals.gems.util.ValidationHelper;
58  import org.apache.velocity.context.Context;
59  
60  /***
61   * This portlet allows a logged on user to change its password.
62   * 
63   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
64   * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
65   * @version $Id: $
66   */
67  public class UserRegistrationPortlet extends AbstractVelocityMessagingPortlet
68  {
69  
70      private PortalAdministration admin;
71  
72      private UserManager userManager;
73  
74      // commonly USED attributes
75  
76      private static final String USER_ATTRIBUTE_EMAIL = "user.business-info.online.email";
77  
78      // Messages
79      private static final String MSG_MESSAGE = "MSG";
80  
81      private static final String MSG_USERINFO = "user";
82  
83      private static final String MSG_REGED_USER_MSG = "registeredUserMsg";
84  
85      // Init Parameters
86      private static final String IP_ROLES = "roles"; // comma separated
87  
88      private static final String IP_GROUPS = "groups"; // comma separated
89  
90      private static final String IP_TEMPLATE_LOCATION = "emailTemplateLocation";
91  
92      private static final String IP_TEMPLATE_NAME = "emailTemplateName";
93  
94      private static final String IP_RULES_NAMES = "rulesNames";
95  
96      private static final String IP_RULES_VALUES = "rulesValues";
97  
98      private static final String IP_REDIRECT_PATH = "redirectPath";
99  
100     private static final String IP_RETURN_URL = "returnURL";
101 
102     private static final String IP_OPTION_EMAILS_SYSTEM_UNIQUE = "Option_Emails_System_Unique";
103 
104     private static final String IP_OPTION_GENERATE_PASSWORDS = "Option_Generate_Passwords";
105 
106     private static final String IP_OPTION_USE_EMAIL_AS_USERNAME = "Option_Use_Email_As_Username";
107 
108     // Context Variables
109     private static final String CTX_RETURN_URL = "returnURL";
110 
111     private static final String CTX_MESSAGE = "MSG";
112 
113     private static final String CTX_USERINFO = "user";
114 
115     private static final String CTX_FIELDS = "fieldsInOrder";
116 
117     private static final String CTX_OPTIONALS = "optionalMap";
118 
119     private static final String CTX_REGED_USER_MSG = "registeredUserMsg";
120 
121     private static final String CTX_OPTION_GENERATE_PASSWORDS = "CTX_Option_Generate_Passwords";
122 
123     private static final String CTX_OPTION_USE_EMAIL_AS_USERNAME = "CTX_Option_Use_Email_As_Username";
124 
125     // Resource Bundle
126     private static final String RB_EMAIL_SUBJECT = "email.subject.registration";
127     
128     private static final String PATH_SEPARATOR = "/";
129 
130     /*** email template to use for merging */
131     private String templateLocation;
132 
133     private String templateName;
134 
135     private JetspeedTemplateLocator templateLocator;
136     
137     /*** localized emailSubject */
138     private String emailSubject = null;
139 
140     /*** path where to redirect to after pressing submit on the form */
141     private String redirectPath;
142 
143     /*** servlet path of the return url to be printed and href'd in email template */
144     private String returnUrlPath;
145 
146     /*** roles */
147     private List roles;
148 
149     /*** groups */
150     private List groups;
151 
152     /*** profile rules */
153     private Map rules;
154 
155     /*** will force the passwords to be generated instead of picked by the user */
156     private boolean optionForceGeneratedPasswords = false;
157 
158     /***
159      * will use cause the portlet to use a user request username instead
160      * otherwise forces emailaddress
161      */
162     private boolean optionForceEmailAsUsername = true;
163 
164     /*** will check to make sure the email address is unique to the system */
165     private boolean optionForceEmailsToBeSystemUnique = true;
166 
167     public void init(PortletConfig config) throws PortletException
168     {
169         super.init(config);
170         admin = (PortalAdministration) getPortletContext().getAttribute(
171                 CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
172         if (null == admin) { throw new PortletException(
173                 "Failed to find the Portal Administration on portlet initialization"); }
174         userManager = (UserManager) getPortletContext().getAttribute(
175                 CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
176         if (null == userManager) { throw new PortletException(
177                 "Failed to find the User Manager on portlet initialization"); }
178 
179         // roles
180         this.roles = getInitParameterList(config, IP_ROLES);
181 
182         // groups
183         this.groups = getInitParameterList(config, IP_GROUPS);
184 
185         // rules (name,value pairs)
186         List names = getInitParameterList(config, IP_RULES_NAMES);
187         List values = getInitParameterList(config, IP_RULES_VALUES);
188         rules = new HashMap();
189         for (int ix = 0; ix < ((names.size() < values.size()) ? names.size()
190                 : values.size()); ix++)
191         {
192             rules.put(names.get(ix), values.get(ix));
193         }
194 
195         this.templateLocation = config.getInitParameter(IP_TEMPLATE_LOCATION);
196         if (templateLocation == null)
197         {
198             templateLocation = "/WEB-INF/view/userreg/";
199         }
200         templateLocation = getPortletContext().getRealPath(templateLocation);
201         this.templateName = config.getInitParameter(IP_TEMPLATE_NAME);
202         if (templateName == null)
203         {
204             templateName = "userRegistrationEmail.vm";
205         }
206         
207         ArrayList roots = new ArrayList(1);
208         roots.add(templateLocation);
209 
210         try
211         {
212             templateLocator = new JetspeedTemplateLocator(roots, "email", getPortletContext().getRealPath("/"));
213             templateLocator.start();
214         }
215         catch (FileNotFoundException e)
216         {
217             throw new PortletException("Could not start the template locator.", e);
218         }
219         
220         // user attributes ?
221 
222         this.optionForceEmailsToBeSystemUnique = Boolean.valueOf(
223                 config.getInitParameter(IP_OPTION_EMAILS_SYSTEM_UNIQUE))
224                 .booleanValue();
225         this.optionForceGeneratedPasswords = Boolean.valueOf(
226                 config.getInitParameter(IP_OPTION_GENERATE_PASSWORDS))
227                 .booleanValue();
228         this.optionForceEmailAsUsername = Boolean.valueOf(
229                 config.getInitParameter(IP_OPTION_USE_EMAIL_AS_USERNAME))
230                 .booleanValue();
231         if (this.optionForceEmailAsUsername)
232         {
233             // just to be sure
234             this.optionForceEmailsToBeSystemUnique = true;
235         }
236         this.returnUrlPath = config.getInitParameter(IP_RETURN_URL);
237         this.redirectPath = config.getInitParameter(IP_REDIRECT_PATH);
238     }
239 
240     public void doEdit(RenderRequest request, RenderResponse response)
241     throws PortletException, IOException
242     {
243         response.setContentType("text/html");
244         doPreferencesEdit(request, response);
245     }
246     
247     public void doView(RenderRequest request, RenderResponse response)
248             throws PortletException, IOException
249     {
250         response.setContentType("text/html");
251         Context context = getContext(request);
252 
253         Object userinfoObject = this
254                 .receiveRenderMessage(request, MSG_USERINFO);
255         context.put(CTX_USERINFO, userinfoObject);
256         context.put(CTX_FIELDS, getListOfNonSpecialFormKeys());
257         context.put(CTX_OPTIONALS, getOptionalMap());
258         context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));
259         String guid = request.getParameter("newUserGUID");
260         if (guid != null)
261         {
262             // we'll ignore the possibility of an invalid guid for now.
263 
264             // NOTE this would be a good place to put the actual registration if
265             // that's the process you want to have happen.
266 
267             ResourceBundle resource = getPortletConfig().getResourceBundle(
268                     request.getLocale());
269             context.put(CTX_REGED_USER_MSG, resource
270                     .getString("success.login_above"));
271         } else
272         {
273             // not a returning url, but perhaps we just got redirected from the
274             // form ?
275             // if this is non-null, then we know that we registered
276             context.put(CTX_REGED_USER_MSG, consumeRenderMessage(request,
277                     MSG_REGED_USER_MSG));
278         }
279         // next two control the existence of some of the fields in the form
280         if (this.optionForceEmailAsUsername)
281         {
282             context.put(CTX_OPTION_USE_EMAIL_AS_USERNAME, "TRUE");
283         }
284         if (this.optionForceGeneratedPasswords)
285         {
286             context.put(CTX_OPTION_GENERATE_PASSWORDS, "TRUE");
287         }
288 
289         super.doView(request, response);
290     }
291 
292     private static final Boolean required = new Boolean(true);
293 
294     private static final Boolean optional = new Boolean(false);
295 
296     private static final Integer IS_STRING = new Integer(1);
297 
298     private static final Integer IS_EMAIL = new Integer(2);
299 
300     private static final Integer IS_PHONE = new Integer(3);
301 
302     private static final Integer IS_URL = new Integer(4);
303 
304     private static final Integer IS_BDATE = new Integer(5);
305 
306     protected List getListOfNonSpecialFormKeys()
307     {
308         List l = new ArrayList();
309         for (int i = 0; i < formKeys.length; i++)
310         {
311             String key = (String) formKeys[i][0];
312             if (key.equals("user.name"))
313             {
314                 // don't put this in
315             } else if (key.equals("user.business-info.online.email"))
316             {
317                 // don't put this in
318             } else if (key.equals("password"))
319             {
320                 // don't put this in
321             } else if (key.equals("verifyPassword"))
322             {
323                 // don't put this in
324             } else
325             {
326                 // but DO add this
327                 l.add(key);
328             }
329         }
330         return l;
331     }
332 
333     protected Map getOptionalMap()
334     {
335         Map m = new HashMap();
336         for (int i = 0; i < formKeys.length; i++)
337         {
338             boolean isRequired = ((Boolean) formKeys[i][1]).booleanValue();
339             if (!isRequired)
340             {
341                 m.put(formKeys[i][0], "");
342             }
343         }
344         return m;
345     }
346     // PLT name, required, max length,  validation type 
347     
348     protected static Object[][] formKeys =
349     { 
350         // the next four items are special cases
351         
352         // this is the offical email used by jetspeed.  You can chnage it, but you have to look around in the code
353         {"user.business-info.online.email", required ,      new Integer(80),        IS_EMAIL},
354         
355         // username is required here 
356         // chould be commented out if email is used as username...
357         {"user.name",         required ,      new Integer(80),        IS_STRING},
358         
359         // These last two are special cases you must have them
360         // comment them out here if you use the generated password option
361         {"password", required, new Integer(80), IS_STRING},
362         {"verifyPassword", required, new Integer(80), IS_STRING},
363     
364         // the following can be placed in any order, and will appear in that order on the page
365         
366         //      All of the following are optional and are stored as user attributes if collected.
367         
368         /*
369         {"user.bdate",          optional ,      new Integer(25),        IS_BDATE},    // Note: store as a string which is a number, time in milliseconds since 1970... see Portlet Spec. 
370         {"user.gender",         optional ,      new Integer(10),        IS_STRING},
371         {"user.employer",         optional ,      new Integer(80),        IS_STRING},
372         */
373         
374         {"user.department",         optional ,      new Integer(80),        IS_STRING},
375         /*
376         {"user.jobtitle",         optional ,      new Integer(80),        IS_STRING},
377         {"user.name.prefix",         optional ,      new Integer(10),        IS_STRING},
378         */
379         {"user.name.given",         optional ,      new Integer(30),        IS_STRING},
380         {"user.name.family",         optional ,      new Integer(30),        IS_STRING},
381         /*
382         {"user.name.middle",         optional ,      new Integer(30),        IS_STRING},
383         {"user.name.suffix",         optional ,      new Integer(10),        IS_STRING},
384         {"user.name.nickName",         optional ,      new Integer(30),        IS_STRING},
385         {"user.home-info.postal.name",         optional ,      new Integer(80),        IS_STRING},
386         {"user.home-info.postal.street",         optional ,      new Integer(80),        IS_STRING},
387         {"user.home-info.postal.city",         optional ,      new Integer(80),        IS_STRING},
388         {"user.home-info.postal.stateprov",         optional ,      new Integer(80),        IS_STRING},
389         {"user.home-info.postal.postalcode",         optional ,      new Integer(80),        IS_STRING},
390         {"user.home-info.postal.country",         optional ,      new Integer(80),        IS_STRING},
391         {"user.home-info.postal.organization",         optional ,      new Integer(80),        IS_STRING},
392         {"user.home-info.telecom.telephone.intcode",         optional ,      new Integer(80),        IS_STRING},
393         {"user.home-info.telecom.telephone.loccode",         optional ,      new Integer(80),        IS_STRING},
394         {"user.home-info.telecom.telephone.number",         optional ,      new Integer(80),        IS_PHONE},
395         {"user.home-info.telecom.telephone.ext",         optional ,      new Integer(80),        IS_STRING},
396         {"user.home-info.telecom.telephone.comment",         optional ,      new Integer(80),        IS_STRING},
397         {"user.home-info.telecom.fax.intcode",         optional ,      new Integer(80),        IS_STRING},
398         {"user.home-info.telecom.fax.loccode",         optional ,      new Integer(80),        IS_STRING},
399         {"user.home-info.telecom.fax.number",         optional ,      new Integer(80),        IS_STRING},
400         {"user.home-info.telecom.fax.ext",         optional ,      new Integer(80),        IS_STRING},
401         {"user.home-info.telecom.fax.comment",         optional ,      new Integer(80),        IS_STRING},
402         {"user.home-info.telecom.mobile.intcode",         optional ,      new Integer(80),        IS_STRING},
403         {"user.home-info.telecom.mobile.loccode",         optional ,      new Integer(80),        IS_STRING},
404         {"user.home-info.telecom.mobile.number",optional ,      new Integer(80),        IS_PHONE},
405         {"user.home-info.telecom.mobile.ext",         optional ,      new Integer(80),        IS_STRING},
406         {"user.home-info.telecom.mobile.comment",         optional ,      new Integer(80),        IS_STRING},
407         {"user.home-info.telecom.pager.intcode",         optional ,      new Integer(80),        IS_STRING},
408         {"user.home-info.telecom.pager.loccode",         optional ,      new Integer(80),        IS_STRING},
409         {"user.home-info.telecom.pager.number",         optional ,      new Integer(80),        IS_PHONE},
410         {"user.home-info.telecom.pager.ext",            optional ,      new Integer(80),        IS_STRING},
411         {"user.home-info.telecom.pager.comment",         optional ,      new Integer(80),        IS_STRING},
412         {"user.home-info.online.email",         optional ,      new Integer(80),        IS_EMAIL},
413         {"user.home-info.online.uri",         optional ,      new Integer(80),        IS_URL},
414         */
415         {"user.business-info.postal.name",         optional ,      new Integer(80),        IS_STRING},
416         {"user.business-info.postal.street",         optional ,      new Integer(80),        IS_STRING},
417         {"user.business-info.postal.city",         optional ,      new Integer(80),        IS_STRING},
418         {"user.business-info.postal.stateprov",         optional ,      new Integer(80),        IS_STRING},
419         {"user.business-info.postal.postalcode",         optional ,      new Integer(80),        IS_STRING},
420         {"user.business-info.postal.country",         optional ,      new Integer(80),        IS_STRING},
421         {"user.business-info.postal.organization",         optional ,      new Integer(80),        IS_STRING},
422         /*
423         {"user.business-info.telecom.telephone.intcode",         optional ,      new Integer(80),        IS_STRING},
424         {"user.business-info.telecom.telephone.loccode",         optional ,      new Integer(80),        IS_STRING},
425         {"user.business-info.telecom.telephone.number",         optional ,      new Integer(80),        IS_PHONE},
426         {"user.business-info.telecom.telephone.ext",         optional ,      new Integer(80),        IS_STRING},
427         {"user.business-info.telecom.telephone.comment",         optional ,      new Integer(80),        IS_STRING},
428         {"user.business-info.telecom.fax.intcode",         optional ,      new Integer(80),        IS_STRING},
429         {"user.business-info.telecom.fax.loccode",         optional ,      new Integer(80),        IS_STRING},
430         {"user.business-info.telecom.fax.number",         optional ,      new Integer(80),        IS_PHONE},
431         {"user.business-info.telecom.fax.ext",         optional ,      new Integer(80),        IS_STRING},
432         {"user.business-info.telecom.fax.comment",         optional ,      new Integer(80),        IS_STRING},
433         {"user.business-info.telecom.mobile.intcode",         optional ,      new Integer(80),        IS_STRING},
434         {"user.business-info.telecom.mobile.loccode",         optional ,      new Integer(80),        IS_STRING},
435         {"user.business-info.telecom.mobile.number",         optional ,      new Integer(80),        IS_PHONE},
436         {"user.business-info.telecom.mobile.ext",         optional ,      new Integer(80),        IS_STRING},
437         {"user.business-info.telecom.mobile.comment",         optional ,      new Integer(80),        IS_STRING},
438         {"user.business-info.telecom.pager.intcode",         optional ,      new Integer(80),        IS_STRING},
439         {"user.business-info.telecom.pager.loccode",         optional ,      new Integer(80),        IS_STRING},
440         {"user.business-info.telecom.pager.number",         optional ,      new Integer(80),        IS_PHONE},
441         {"user.business-info.telecom.pager.ext",            optional ,      new Integer(80),        IS_STRING},
442         {"user.business-info.telecom.pager.comment",         optional ,      new Integer(80),        IS_STRING},
443 //      --- special case see above  user.business-info.online.email 
444         {"user.business-info.online.uri", optional ,      new Integer(80),        IS_URL},
445         */
446     };
447 
448     protected boolean validateFormValue(String value, Integer length,
449             Integer validationType)
450     {
451 
452         if (validationType.equals(IS_STRING))
453         {
454             if (!ValidationHelper.isAny(value, true, length.intValue())) { return false; }
455         } else if (validationType.equals(IS_EMAIL))
456         {
457             if (!ValidationHelper
458                     .isEmailAddress(value, true, length.intValue())) { return false; }
459         } else if (validationType.equals(IS_PHONE))
460         {
461             if (!ValidationHelper.isPhoneNumber(value, true, length.intValue())) { return false; }
462         } else if (validationType.equals(IS_URL))
463         {
464             if (!ValidationHelper.isURL(value, true, length.intValue())) { return false; }
465         } else if (validationType.equals(IS_BDATE))
466         {
467             if (!ValidationHelper.isValidDatetime(value)) { return false; }
468         } else
469         {
470             // unkown type assume string for now
471             if (!ValidationHelper.isAny(value, true, length.intValue())) { return false; }
472         }
473         return true;
474 
475     }
476 
477     protected String convertIfNeed(String key, String value)
478     {
479         if ("user.bdate".equals(key))
480         {
481             // this one needs conversion
482             Date d = ValidationHelper.parseDate(value);
483             long timeInmS = d.getTime();
484             return "" + timeInmS;
485         }
486         return value;
487     }
488 
489     public void processAction(ActionRequest actionRequest,
490             ActionResponse actionResponse) throws PortletException, IOException
491     {
492         List errors = new LinkedList();
493 
494         Map userAttributes = new HashMap();
495 
496         Map userInfo = new HashMap();
497         ResourceBundle resource = getPortletConfig().getResourceBundle(
498                 actionRequest.getLocale());
499 
500         if (actionRequest.getPortletMode() == PortletMode.EDIT)
501         {
502             PortletPreferences prefs = actionRequest.getPreferences();
503             PreferencesHelper.requestParamsToPreferences(actionRequest);
504             prefs.store();
505             actionResponse.setPortletMode(PortletMode.VIEW);
506             return;
507         }
508         
509         try
510         {
511 
512             for (int i = 0; i < formKeys.length; i++)
513             {
514                 try
515                 {
516                     String key = (String) formKeys[i][0];
517                     Boolean isRequired = (Boolean) formKeys[i][1];
518                     String value = actionRequest.getParameter(key);
519                     if ((value != null) && (value.length() > 0))
520                     {
521 
522                         userInfo.put(key, value);
523 
524                         // do some validation
525                         if (!validateFormValue(value, (Integer) formKeys[i][2],
526                                 (Integer) formKeys[i][3]))
527                         {
528                             errors.add(resource
529                                     .getString("error.invalid-format." + key));
530                         }
531 
532                         if (key.startsWith("user."))
533                         {
534                             value = convertIfNeed(key, value);
535                             // we'll assume that these map back to PLT.D values
536                             userAttributes.put(key, value);
537                         }
538                     } else
539                     {
540                         // don't have that value or it's too short... is it
541                         // required ?
542                         if (isRequired.booleanValue())
543                         {
544                             errors.add(resource.getString("error.lacking."
545                                     + key));
546                         }
547                         // place an empty version in userInfo anyway
548                         // so that the template will display the correct fields
549                         userInfo.put(key, "");
550                     }
551                 } catch (MissingResourceException mre)
552                 {
553                     errors.add(resource.getString("error.failed_to_add")
554                             + mre.toString());
555                 }
556 
557             }
558             // publish the whole map so we can reload the form values on error.
559             publishRenderMessage(actionRequest, MSG_USERINFO, userInfo);
560 
561             // These next checks may duplicate previous checks.
562             // however this is a double check given the nature of the values and
563             // how they are used.
564             if (this.optionForceEmailAsUsername)
565             {
566                 // email is something special
567                 if (!ValidationHelper.isEmailAddress((String) userInfo
568                         .get(USER_ATTRIBUTE_EMAIL), true, 80))
569                 {
570                     errors.add(resource.getString("error.invalid-format."
571                             + USER_ATTRIBUTE_EMAIL));
572                 }
573             } else
574             {
575                 if (!ValidationHelper.isAny((String) userInfo.get("user.name"),
576                         true, 80))
577                 {
578                     errors.add(resource.getString("error.lacking.user.name"));
579                 }
580             }
581 
582             // if we're not generating make sure it's real
583             if (!this.optionForceGeneratedPasswords)
584             {
585                 if (!ValidationHelper.isAny((String) userInfo.get("password"),
586                         true, 25))
587                 {
588                     errors.add(resource.getString("error.lacking.password"));
589                 }
590             }
591 
592             if (optionForceEmailAsUsername)
593             {
594                 // force user.name to be same as email
595                 userInfo.put("user.name", userInfo.get(USER_ATTRIBUTE_EMAIL));
596             }
597 
598             boolean userIdExistsFlag = true;
599             try
600             {
601                 userManager.getUser((String) userInfo.get("user.name"));
602             } catch (SecurityException e)
603             {
604                 userIdExistsFlag = false;
605             }
606             //
607             if (userIdExistsFlag)
608             {
609                 errors.add(resource.getString("error.userid_already_exists"));
610                 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
611                 return;
612             }
613             if (optionForceEmailsToBeSystemUnique)
614             {
615                 boolean emailExistsFlag = true;
616                 User user = null;
617                 try
618                 {
619                     user = admin.lookupUserFromEmail((String) userInfo
620                             .get(USER_ATTRIBUTE_EMAIL));
621                 } catch (AdministrationEmailException e1)
622                 {
623                     emailExistsFlag = false;
624                 }
625                 if ((emailExistsFlag) || (user != null))
626                 {
627                     errors
628                             .add(resource
629                                     .getString("error.email_already_exists"));
630                     publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
631                     return;
632                 }
633 
634             }
635 
636             try
637             {
638                 if (optionForceGeneratedPasswords)
639                 {
640                     String password = admin.generatePassword();
641                     userInfo.put("password", password);
642                 } else
643                 {
644                     if (userInfo.get("password").equals(
645                             userInfo.get("verifyPassword")))
646                     {
647 
648                     } else
649                     {
650                         errors.add(resource
651                                 .getString("error.two_passwords_do_not_match"));
652                         publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
653                         return;
654                     }
655                 }
656             } catch (Exception e)
657             {
658                 errors.add(resource.getString("error.failed_to_add")
659                         + e.toString());
660                 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
661             }
662             // make sure no errors have occurred
663             if (errors.size() > 0)
664             {
665                 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
666                 return;
667             }
668 
669             // Ok, we think we're good to go, let's create the user!
670             try
671             {
672                 PortletPreferences prefs = actionRequest.getPreferences();
673                 String template = prefs.getValue("newUserTemplateDirectory", "");
674                 if (template.trim().length() == 0)
675                     template = null;
676                 String subsiteRootFolder = prefs.getValue("subsiteRootFolder", "");
677                 if (subsiteRootFolder.trim().length() == 0)
678                     subsiteRootFolder = null;
679                 List prefRoles = getPreferencesList(prefs, IP_ROLES);
680                 if (prefRoles.isEmpty())
681                     prefRoles = this.roles;
682                 List prefGroups = getPreferencesList(prefs, IP_GROUPS);
683                 if (prefGroups.isEmpty())
684                     prefGroups = this.groups;
685                 
686                 List names = getPreferencesList(prefs, IP_RULES_NAMES);
687                 List values = getPreferencesList(prefs, IP_RULES_VALUES);
688                 Map profileRules = new HashMap();
689                 for (int ix = 0; ix < ((names.size() < values.size()) ? names.size()
690                         : values.size()); ix++)
691                 {
692                     profileRules.put(names.get(ix), values.get(ix));
693                 }
694                 if (profileRules.isEmpty())
695                     profileRules = this.rules;
696                 
697                 admin.registerUser((String) userInfo.get("user.name"),
698                         (String) userInfo.get("password"), prefRoles,
699                         prefGroups, userAttributes, // note use of only
700                                                         // PLT.D values here.
701                         profileRules, template, subsiteRootFolder); 
702                 
703                 String urlGUID = ForgottenPasswordPortlet.makeGUID(
704                         (String) userInfo.get("user.name"), (String) userInfo
705                                 .get("password"));
706 
707                 userInfo.put(CTX_RETURN_URL, generateReturnURL(actionRequest,
708                         actionResponse, urlGUID));
709 
710                 String templ = getTemplatePath(actionRequest, actionResponse);
711 
712                 if (templ == null) { throw new Exception(
713                         "email template not available"); }
714 
715                 boolean sendEmail = prefs.getValue("SendEmail", "true").equals("true");
716                 if (sendEmail)
717                 {
718                     admin.sendEmail(getPortletConfig(), (String) userInfo
719                             .get(USER_ATTRIBUTE_EMAIL),
720                             getEmailSubject(actionRequest), templ, userInfo);
721                 }
722                 
723                 if ((this.optionForceEmailAsUsername)
724                         || (this.optionForceGeneratedPasswords))
725                 {
726                     publishRenderMessage(actionRequest, MSG_REGED_USER_MSG,
727                             resource.getString("success.check_your_email"));
728                 } else
729                 {
730                     publishRenderMessage(actionRequest, MSG_REGED_USER_MSG,
731                             resource.getString("success.login_above"));
732                 }
733 
734                 // put an empty map to "erase" all the user info going forward
735                 publishRenderMessage(actionRequest, MSG_USERINFO, new HashMap());
736 
737                 actionResponse.sendRedirect(this.generateRedirectURL(
738                         actionRequest, actionResponse));
739 
740             } catch (Exception e)
741             {
742                 errors.add(resource.getString("error.failed_to_add")
743                         + e.toString());
744                 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
745             }
746         } catch (MissingResourceException mre)
747         {
748             errors.add(resource.getString("error.failed_to_add")
749                     + mre.toString());
750             publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
751         } catch (Exception e)
752         {
753             errors
754                     .add(resource.getString("error.failed_to_add")
755                             + e.toString());
756             publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
757         }
758 
759     }
760 
761     protected String getEmailSubject(PortletRequest request)
762     {
763         ResourceBundle resource = getPortletConfig().getResourceBundle(
764                 request.getLocale());
765         try
766         {
767             this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
768         } catch (java.util.MissingResourceException mre)
769         {
770             this.emailSubject = null;
771         }
772         if (this.emailSubject == null)
773             this.emailSubject = "Registration Confirmation";
774         return this.emailSubject;
775     }
776 
777     protected List getInitParameterList(PortletConfig config, String ipName)
778     {
779         String temp = config.getInitParameter(ipName);
780         if (temp == null) return new ArrayList();
781 
782         String[] temps = temp.split("//,");
783         for (int ix = 0; ix < temps.length; ix++)
784             temps[ix] = temps[ix].trim();
785 
786         return Arrays.asList(temps);
787     }
788 
789     protected List getPreferencesList(PortletPreferences prefs, String prefName)
790     {
791         String temp = prefs.getValue(prefName, "");
792         if (temp == null || temp.trim().length() == 0) return new ArrayList();
793 
794         String[] temps = temp.split("//,");
795         for (int ix = 0; ix < temps.length; ix++)
796             temps[ix] = temps[ix].trim();
797 
798         return Arrays.asList(temps);
799     }
800     
801     protected String generateReturnURL(PortletRequest request,
802             PortletResponse response, String urlGUID)
803     {
804         String fullPath = this.returnUrlPath + "?newUserGUID=" + urlGUID;
805         // NOTE: getPortalURL will encode the fullPath for us
806         String url = admin.getPortalURL(request, response, fullPath);
807         return url;
808     }
809 
810     protected String generateRedirectURL(PortletRequest request,
811             PortletResponse response)
812     {
813         return admin.getPortalURL(request, response, this.redirectPath);
814     }
815  
816     
817     protected String getTemplatePath(ActionRequest request, ActionResponse response)
818     {
819         if (templateLocator == null)
820         {
821             return templateLocation + PATH_SEPARATOR + templateName;
822         }
823 
824         RequestContext requestContext = (RequestContext) request
825                 .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
826         Locale locale = request.getLocale();
827 
828         try
829         {
830             LocatorDescriptor locator = templateLocator.createLocatorDescriptor("email");
831             locator.setName(templateName);
832             locator.setMediaType(requestContext.getMediaType());
833             locator.setLanguage(locale.getLanguage());
834             locator.setCountry(locale.getCountry());
835             TemplateDescriptor template = templateLocator.locateTemplate(locator);
836 
837             return template.getAppRelativePath();
838         }
839         catch (TemplateLocatorException e)
840         {
841             return templateLocation + PATH_SEPARATOR + templateName;
842         }
843     }
844 }