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