]> git.mxchange.org Git - jjobs-war.git/blobdiff - src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionBean.java
Please cherry-pick:
[jjobs-war.git] / src / java / org / mxchange / jjobs / beans / user / JobsUserWebSessionBean.java
index eb4e781f6b5a3084bf89032a8d5a5480e9e7c7df..5c9c1a9ccd21e790e239618f9ec517e57efda0e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Roland Haeder
+ * Copyright (C) 2016, 2017 Roland Häder
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
 package org.mxchange.jjobs.beans.user;
 
 import java.text.MessageFormat;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
 import javax.annotation.PostConstruct;
+import javax.ejb.EJB;
 import javax.enterprise.context.SessionScoped;
 import javax.enterprise.event.Event;
 import javax.enterprise.event.Observes;
@@ -30,34 +31,41 @@ import javax.faces.context.FacesContext;
 import javax.faces.view.facelets.FaceletException;
 import javax.inject.Inject;
 import javax.inject.Named;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
 import org.mxchange.jcontacts.contact.Contact;
-import org.mxchange.jcontacts.contact.ContactSessionBeanRemote;
-import org.mxchange.jcontacts.events.contact.add.AdminAddedContactEvent;
+import org.mxchange.jcoreee.events.locale.ObservableLocaleChangeEvent;
 import org.mxchange.jjobs.beans.BaseJobsController;
 import org.mxchange.jjobs.beans.contact.JobsContactWebSessionController;
-import org.mxchange.jjobs.beans.login.JobsUserLoginWebSessionController;
-import org.mxchange.jjobs.beans.register.JobsUserRegisterWebSessionController;
-import org.mxchange.jusercore.events.login.UserLoggedInEvent;
-import org.mxchange.jusercore.events.registration.UserRegisteredEvent;
-import org.mxchange.jusercore.events.user.add.AdminAddedUserEvent;
-import org.mxchange.jusercore.events.user.update.AdminUpdatedUserDataEvent;
+import org.mxchange.jjobs.beans.features.JobsFeaturesWebApplicationController;
+import org.mxchange.jjobs.beans.localization.JobsLocalizationSessionController;
+import org.mxchange.jjobs.beans.user.login.JobsUserLoginWebSessionController;
+import org.mxchange.jusercore.events.user.add.ObservableAdminAddedUserEvent;
+import org.mxchange.jusercore.events.user.clear.password.ObservableClearUserPasswordEvent;
+import org.mxchange.jusercore.events.user.clear.username.ObservableClearUserNameEvent;
+import org.mxchange.jusercore.events.user.created.ObservableCreatedUserEvent;
+import org.mxchange.jusercore.events.user.delete.ObservableAdminDeletedUserEvent;
+import org.mxchange.jusercore.events.user.linked.ObservableAdminLinkedUserEvent;
+import org.mxchange.jusercore.events.user.locked.ObservableAdminLockedUserEvent;
+import org.mxchange.jusercore.events.user.unlocked.ObservableAdminUnlockedUserEvent;
+import org.mxchange.jusercore.events.user.update.ObservableAdminUpdatedUserDataEvent;
+import org.mxchange.jusercore.events.user.update.ObservableUpdatedUserPersonalDataEvent;
 import org.mxchange.jusercore.events.user.update.UpdatedUserPersonalDataEvent;
-import org.mxchange.jusercore.events.user.update.UserUpdatedPersonalDataEvent;
+import org.mxchange.jusercore.exceptions.UserEmailAddressNotFoundException;
 import org.mxchange.jusercore.exceptions.UserNotFoundException;
-import org.mxchange.jusercore.exceptions.UserPasswordMismatchException;
 import org.mxchange.jusercore.model.user.LoginUser;
 import org.mxchange.jusercore.model.user.User;
 import org.mxchange.jusercore.model.user.UserSessionBeanRemote;
-import org.mxchange.jusercore.model.user.UserUtils;
 import org.mxchange.jusercore.model.user.profilemodes.ProfileMode;
+import org.mxchange.juserlogincore.events.confirmation.ObservableUserConfirmedAccountEvent;
+import org.mxchange.juserlogincore.events.login.ObservableUserLoggedInEvent;
+import org.mxchange.juserlogincore.events.registration.ObservableUserRegisteredEvent;
+import org.mxchange.juserlogincore.events.user.password_change.ObservableUpdatedUserPasswordEvent;
+import org.mxchange.juserlogincore.exceptions.UserPasswordMismatchException;
+import org.mxchange.juserlogincore.login.UserLoginUtils;
 
 /**
- * A user bean (controller)
+ * A user controller (bean)
  * <p>
- * @author Roland Haeder<roland@mxchange.org>
+ * @author Roland Häder<roland@mxchange.org>
  */
 @Named ("userController")
 @SessionScoped
@@ -68,11 +76,6 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
         */
        private static final long serialVersionUID = 542_145_347_916L;
 
-       /**
-        * Contact EJB
-        */
-       private ContactSessionBeanRemote contactBean;
-
        /**
         * General contact controller
         */
@@ -80,27 +83,34 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
        private JobsContactWebSessionController contactController;
 
        /**
-        * Registration controller
+        * Features controller
         */
        @Inject
-       private JobsUserRegisterWebSessionController registerController;
+       private JobsFeaturesWebApplicationController featureController;
 
        /**
-        * A list of all selectable contacts
+        * Locale instance
         */
-       private List<Contact> selectableContacts;
+       private Locale locale;
+
+       /**
+        * Localization controller
+        */
+       @Inject
+       private JobsLocalizationSessionController localizationController;
 
        /**
         * Event being fired when user updated personal data
         */
        @Inject
        @Any
-       private Event<UpdatedUserPersonalDataEvent> updatedPersonalDataEvent;
+       private Event<ObservableUpdatedUserPersonalDataEvent> updatedPersonalDataEvent;
 
        /**
         * Remote user bean
         */
-       private final UserSessionBeanRemote userBean;
+       @EJB (lookup = "java:global/jjobs-ejb/user!org.mxchange.jusercore.model.user.UserSessionBeanRemote")
+       private UserSessionBeanRemote userBean;
 
        /**
         * User id
@@ -113,7 +123,7 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
        private List<User> userList;
 
        /**
-        * Login bean (controller)
+        * Login controller (bean)
         */
        @Inject
        private JobsUserLoginWebSessionController userLoginController;
@@ -129,12 +139,12 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
        private List<String> userNameList;
 
        /**
-        * User password (unencrypted from web form)
+        * User password (clear-text from web form)
         */
        private String userPassword;
 
        /**
-        * User password repeated (unencrypted from web form)
+        * User password repeated (clear-text from web form)
         */
        private String userPasswordRepeat;
 
@@ -145,6 +155,9 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
 
        /**
         * A list of all public user profiles
+        * <p>
+        * @TODO Hmm, makes that sense? Having visible user list in current
+        * (session-scoped) user's visible user list?
         */
        private List<User> visibleUserList;
 
@@ -152,81 +165,156 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
         * Default constructor
         */
        public JobsUserWebSessionBean () {
-               // Try it
-               try {
-                       // Get initial context
-                       Context context = new InitialContext();
-
-                       // Try to lookup
-                       this.userBean = (UserSessionBeanRemote) context.lookup("java:global/jjobs-ejb/user!org.mxchange.jusercore.model.user.UserSessionBeanRemote"); //NOI18N
+               // Call super constructor
+               super();
+       }
 
-                       // Try to lookup
-                       this.contactBean = (ContactSessionBeanRemote) context.lookup("java:global/jjobs-ejb/contact!org.mxchange.jcontacts.contact.ContactSessionBeanRemote"); //NOI18N
-               } catch (final NamingException e) {
-                       // Throw again
-                       throw new FaceletException(e);
+       /**
+        * Event observer for newly added users by administrator
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterAdminAddedUserEvent (@Observes final ObservableAdminAddedUserEvent event) {
+               // event should not be null
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getAddedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.addedUser is null"); //NOI18N
+               } else if (event.getAddedUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.addedUser.userId is null"); //NOI18N
+               } else if (event.getAddedUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getAddedUser(), event.getAddedUser().getUserId())); //NOI18N
                }
+
+               // Update user list
+               this.updateList(event.getAddedUser());
+
+               // Clear all data
+               this.clear();
+
+               // Set user id again
+               this.setUserId(event.getAddedUser().getUserId());
        }
 
-       @Override
-       public void afterAdminAddedContact (@Observes final AdminAddedContactEvent event) {
-               // The event must be valid
+       /**
+        * Event observer for deleted user accounts (by administrator)
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterAdminDeletedUserEvent (@Observes final ObservableAdminDeletedUserEvent event) {
+               // event should not be null
                if (null == event) {
                        // Throw NPE
                        throw new NullPointerException("event is null"); //NOI18N
-               } else if (event.getAddedContact() == null) {
-                       // Throw again ...
-                       throw new NullPointerException("event.addedContact is null"); //NOI18N
-               } else if (event.getAddedContact().getContactId() == null) {
-                       // ... and again
-                       throw new NullPointerException("event.addedContact.customerId is null"); //NOI18N
-               } else if (event.getAddedContact().getContactId() < 1) {
-                       // Not valid
-                       throw new IllegalArgumentException(MessageFormat.format("event.addedContact.customerId={0} is not valid", event.getAddedContact().getContactId())); //NOI18N //NOI18N
+               } else if (event.getDeletedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.deletedUser is null"); //NOI18N
+               } else if (event.getDeletedUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.deletedUser.userId is null"); //NOI18N
+               } else if (event.getDeletedUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getDeletedUser(), event.getDeletedUser().getUserId())); //NOI18N
                }
 
-               // Call other method
-               this.selectableContacts.add(event.getAddedContact());
-       }
+               // Update user list
+               this.removeFromList(event.getDeletedUser());
 
-       @Override
-       public void afterAdminAddedUserEvent (@Observes final AdminAddedUserEvent event) {
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterAdminAddedUserEvent: event={0} - CALLED!", event)); //NOI18N
+               // Clear all data
+               this.clear();
+       }
 
+       /**
+        * Event observer for linked users with existing contact data
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterAdminLinkedUserEvent (@Observes final ObservableAdminLinkedUserEvent event) {
                // event should not be null
                if (null == event) {
                        // Throw NPE
                        throw new NullPointerException("event is null"); //NOI18N
-               } else if (event.getAddedUser() == null) {
+               } else if (event.getLinkedUser() == null) {
                        // Throw NPE again
-                       throw new NullPointerException("event.addedUser is null"); //NOI18N
-               } else if (event.getAddedUser().getUserId() == null) {
+                       throw new NullPointerException("event.linkedUser is null"); //NOI18N
+               } else if (event.getLinkedUser().getUserId() == null) {
                        // userId is null
-                       throw new NullPointerException("event.addedUser.userId is null"); //NOI18N
-               } else if (event.getAddedUser().getUserId() < 1) {
+                       throw new NullPointerException("event.linkedUser.userId is null"); //NOI18N
+               } else if (event.getLinkedUser().getUserId() < 1) {
                        // Not avalid id
-                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getAddedUser(), event.getAddedUser().getUserId())); //NOI18N
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLinkedUser(), event.getLinkedUser().getUserId())); //NOI18N
                }
 
-               // Add user to local list
-               this.userList.add(event.getAddedUser());
+               // Update user list
+               this.updateList(event.getLinkedUser());
 
                // Clear all data
                this.clear();
 
                // Set user id again
-               this.setUserId(event.getAddedUser().getUserId());
+               this.setUserId(event.getLinkedUser().getUserId());
+       }
 
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println("UserWebBean:afterAdminAddedUserEvent: EXIT!"); //NOI18N
+       /**
+        * Event observer for locked users
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterAdminLockedUserEvent (@Observes final ObservableAdminLockedUserEvent event) {
+               // event should not be null
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getLockedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.lockedUser is null"); //NOI18N
+               } else if (event.getLockedUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.lockedUser.userId is null"); //NOI18N
+               } else if (event.getLockedUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLockedUser(), event.getLockedUser().getUserId())); //NOI18N
+               }
+
+               // Update user list
+               this.updateList(event.getLockedUser());
        }
 
-       @Override
-       public void afterAdminUpdatedUserDataEvent (@Observes final AdminUpdatedUserDataEvent event) {
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterAdminUpdatedUserEvent: event={0} - CALLED!", event)); //NOI18N
+       /**
+        * Event observer for unlocked users
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterAdminUnlockedUserEvent (@Observes final ObservableAdminUnlockedUserEvent event) {
+               // event should not be null
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getUnlockedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.unlockedUser is null"); //NOI18N
+               } else if (event.getUnlockedUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.unlockedUser.userId is null"); //NOI18N
+               } else if (event.getUnlockedUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getUnlockedUser(), event.getUnlockedUser().getUserId())); //NOI18N
+               }
 
+               // Update user list
+               this.updateList(event.getUnlockedUser());
+       }
+
+       /**
+        * Event observer for updated user data by administrator
+        * <p>
+        * @param event Event being updated
+        */
+       public void afterAdminUpdatedUserDataEvent (@Observes final ObservableAdminUpdatedUserDataEvent event) {
                // event should not be null
                if (null == event) {
                        // Throw NPE
@@ -242,21 +330,151 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                        throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getUpdatedUser(), event.getUpdatedUser().getUserId())); //NOI18N
                }
 
-               // Update list
+               // Update user list
                this.updateList(event.getUpdatedUser());
 
                // Clear all data
                this.clear();
+       }
 
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println("UserWebBean:afterAdminUpdatedUserEvent: EXIT!"); //NOI18N
+       /**
+        * Event observer for when a bean helper has successfully created a user
+        * instance, means the user exists. If the user does not exist, this event
+        * should not fire but instead a proper exception must be thrown.
+        * <p>
+        * @param event User created event
+        */
+       public void afterCreatedUserEvent (@Observes final ObservableCreatedUserEvent event) {
+               // Is the instance valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getCreatedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.createdUser is null"); //NOI18N
+               } else if (event.getCreatedUser().getUserId() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.createdUser.userId is null"); //NOI18N
+               } else if (event.getCreatedUser().getUserId() < 1) {
+                       // Throw NPE again
+                       throw new NullPointerException(MessageFormat.format("event.createdUser.userId={0} is not valid", event.getCreatedUser().getUserId())); //NOI18N
+               }
+
+               // Get user instance
+               User user = event.getCreatedUser();
+
+               // Set all fields here
+               this.copyUser(user);
        }
 
-       @Override
-       public void afterRegistrationEvent (@Observes final UserRegisteredEvent event) {
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterRegistration: event={0} - CALLED!", event)); //NOI18N
+       /**
+        * Observer method for events being fired when the application's locale has
+        * been changed.
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterLocaleChangeEvent (@Observes final ObservableLocaleChangeEvent event) {
+               // Is the parameter valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null");
+               } else if (event.getLocale() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.locale is null");
+               }
+
+               // Set it here
+               this.setLocale(event.getLocale());
+       }
 
+       /**
+        * Event observer when user confirmed account.
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterUserConfirmedAccountEvent (@Observes final ObservableUserConfirmedAccountEvent event) {
+               // event should not be null
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getConfirmedUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.confirmedUser is null"); //NOI18N
+               } else if (event.getConfirmedUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.confirmedUser.userId is null"); //NOI18N
+               } else if (event.getConfirmedUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getConfirmedUser(), event.getConfirmedUser().getUserId())); //NOI18N
+               }
+
+               // Update user list
+               this.updateList(event.getConfirmedUser());
+       }
+
+       /**
+        * Event observer for logged-in user
+        * <p>
+        * @param event Event instance
+        */
+       public void afterUserLoginEvent (@Observes final ObservableUserLoggedInEvent event) {
+               // event should not be null
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getLoggedInUser() == null) {
+                       // Throw NPE again
+                       throw new NullPointerException("event.registeredUser is null"); //NOI18N
+               } else if (event.getLoggedInUser().getUserId() == null) {
+                       // userId is null
+                       throw new NullPointerException("event.registeredUser.userId is null"); //NOI18N
+               } else if (event.getLoggedInUser().getUserId() < 1) {
+                       // Not avalid id
+                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLoggedInUser(), event.getLoggedInUser().getUserId())); //NOI18N
+               }
+
+               // "Cache" user instance
+               User loggedInUser = event.getLoggedInUser();
+
+               // Copy all data to this bean
+               this.copyUser(loggedInUser);
+
+               // Is the user visible?
+               if (Objects.equals(loggedInUser.getUserProfileMode(), ProfileMode.PUBLIC)) {
+                       // Yes, then add user
+                       this.visibleUserList.add(loggedInUser);
+               }
+       }
+
+       /**
+        * Event observer for user password changes
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterUserPasswordChangedEvent (@Observes final ObservableUpdatedUserPasswordEvent event) {
+               // Is it valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getUserPassword() == null) {
+                       // Throw NPE
+                       throw new NullPointerException("event.userPassword is null"); //NOI18N
+               } else if (event.getUserPassword().isEmpty()) {
+                       // Throw NPE
+                       throw new IllegalArgumentException("event.userPassword is empty"); //NOI18N
+               }
+
+               // Set it here
+               this.setUserPassword(event.getUserPassword());
+               this.setUserPasswordRepeat(event.getUserPassword());
+       }
+
+       /**
+        * Event observer for new user registrations
+        * <p>
+        * @param event User registration event
+        */
+       public void afterUserRegistrationEvent (@Observes final ObservableUserRegisteredEvent event) {
                // event should not be null
                if (null == event) {
                        // Throw NPE
@@ -275,17 +493,14 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                // Get user instance
                User registeredUser = event.getRegisteredUser();
 
-               // Debug message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterRegistration: registeredUser={0}", registeredUser)); //NOI18N
-
                // Copy all data from registered->user
                this.copyUser(registeredUser);
 
                // Clear all data
                this.clear();
 
-               // Add user to local list
-               this.userList.add(registeredUser);
+               // Update user list
+               this.updateList(registeredUser);
 
                // Add user name
                this.addUserName(registeredUser);
@@ -298,43 +513,40 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
 
                // Set user id again
                this.setUserId(registeredUser.getUserId());
-
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println("UserWebBean:afterRegistration: EXIT!"); //NOI18N
        }
 
-       @Override
-       public void afterUserLogin (final @Observes UserLoggedInEvent event) {
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterUserLogin: event={0} - CALLED!", event)); //NOI18N
-
-               // event should not be null
+       /**
+        * Method being call after user's password has been updated (and history
+        * entry has been created).
+        * <p>
+        * @param event Event being observed
+        */
+       public void afterUserUpdatedPasswordEvent (@Observes final ObservableUpdatedUserPasswordEvent event) {
+               // Check parameter
                if (null == event) {
                        // Throw NPE
                        throw new NullPointerException("event is null"); //NOI18N
-               } else if (event.getLoggedInUser() == null) {
+               } else if (event.getPasswordHistory() == null) {
                        // Throw NPE again
-                       throw new NullPointerException("event.registeredUser is null"); //NOI18N
-               } else if (event.getLoggedInUser().getUserId() == null) {
-                       // userId is null
-                       throw new NullPointerException("event.registeredUser.userId is null"); //NOI18N
-               } else if (event.getLoggedInUser().getUserId() < 1) {
-                       // Not avalid id
-                       throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLoggedInUser(), event.getLoggedInUser().getUserId())); //NOI18N
+                       throw new NullPointerException("event.passwordHistory is null"); //NOI18N
+               } else if (event.getPasswordHistory().getUserPasswordHistoryId() == null) {
+                       // ... and again
+                       throw new NullPointerException("event.passwordHistory.userPasswordHistoryId is null"); //NOI18N
+               } else if (event.getPasswordHistory().getUserPasswordHistoryId() < 1) {
+                       // Invalid value
+                       throw new IllegalArgumentException(MessageFormat.format("event.passwordHistory.userPasswordHistoryId={0} is in valid", event.getPasswordHistory().getUserPasswordHistoryId())); //NOI18N
                }
 
-               // Copy all data to this bean
-               this.copyUser(event.getLoggedInUser());
-
-               // Re-initialize list
-               this.visibleUserList = this.userBean.allMemberPublicVisibleUsers();
-
-               // Trace message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("UserWebBean:afterUserLogin: this.visibleUserList.size()={0} - EXIT!", this.visibleUserList.size())); //NOI18N
+               // Update user list
+               this.updateList(event.getPasswordHistory().getUserPasswordHistoryUser());
        }
 
-       @Override
-       public void afterUserUpdatedPersonalData (@Observes final UpdatedUserPersonalDataEvent event) {
+       /**
+        * Listens to fired event when user updated personal data
+        * <p>
+        * @param event Event being fired
+        */
+       public void afterUserUpdatedPersonalDataEvent (@Observes final ObservableUpdatedUserPersonalDataEvent event) {
                // Check parameter
                if (null == event) {
                        // Throw NPE
@@ -350,24 +562,58 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                        throw new IllegalArgumentException(MessageFormat.format("event.updatedUser.userId={0} is in valid", event.getUpdatedUser().getUserId())); //NOI18N
                }
 
-               // All fine, so update list
+               // Update user list
                this.updateList(event.getUpdatedUser());
        }
 
        @Override
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
        public List<User> allUsers () {
                // Return it
-               return Collections.unmodifiableList(this.userList);
+               return this.userList;
        }
 
        @Override
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
        public List<User> allVisibleUsers () {
                // Return it
-               return Collections.unmodifiableList(this.visibleUserList);
+               return this.visibleUserList;
+       }
+
+       /**
+        * Event observer for when a user name should be cleared
+        * <p>
+        * @param event Event being fired
+        */
+       public void clearUserNameEvent (@Observes final ObservableClearUserNameEvent event) {
+               // Is it valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null");
+               }
+
+               // Clear it
+               this.clearUserName();
+       }
+
+       /**
+        * Event observer for when both user passwords should be cleared
+        * <p>
+        * @param event Event being fired
+        */
+       public void clearUserPasswordEvent (@Observes final ObservableClearUserPasswordEvent event) {
+               // Is it valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null");
+               }
+
+               // Clear it
+               this.clearUserPasswords();
        }
 
        @Override
-       public User createUserInstance () {
+       public User createUserInstance (final boolean createContactData) {
                // Trace message
                //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("{0}.createUserInstance: CALLED!", this.getClass().getSimpleName()));
 
@@ -375,7 +621,7 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                assert (this.isRequiredPersonalDataSet()) : "not all personal data is set"; //NOI18N
 
                // Create new user instance
-               User localUser = new LoginUser();
+               User user = new LoginUser();
 
                // Is user name required?
                if (!this.isUserNameRequired()) {
@@ -387,31 +633,33 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                        this.setUserProfileMode(ProfileMode.INVISIBLE);
 
                        // Generate random password
-                       String randomPassword = UserUtils.createRandomPassword(JobsUserWebSessionController.MINIMUM_PASSWORD_LENGTH);
+                       String randomPassword = UserLoginUtils.createRandomPassword(JobsUserWebSessionController.MINIMUM_PASSWORD_LENGTH);
 
                        // Set random password
                        this.setUserPassword(randomPassword);
                        this.setUserPasswordRepeat(randomPassword);
                }
 
-               // Set user name and mode
-               localUser.setUserName(this.getUserName());
-               localUser.setUserProfileMode(this.getUserProfileMode());
-
-               // Create contact instance
-               Contact contact = this.contactController.createContactInstance();
+               // Set user name profile mode and locale
+               user.setUserName(this.getUserName());
+               user.setUserProfileMode(this.getUserProfileMode());
+               user.setUserLocale(this.getLocale());
 
-               // Debug message
-               //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("{0}.createUserInstance: contact={1}", this.getClass().getSimpleName(), contact));
+               // Is multiple registration page
+               if ((createContactData) || (!this.featureController.isFeatureEnabled("user_register_multiple_page"))) { //NOI18N
+                       // Create contact instance
+                       Contact contact = this.contactController.createContactInstance();
 
-               // Set contact in user
-               localUser.setUserContact(contact);
+                       // Debug message
+                       //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("{0}.createUserInstance: contact={1}", this.getClass().getSimpleName(), contact));
+                       // Set contact in user
+                       user.setUserContact(contact);
+               }
 
                // Trace message
                //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("{0}.createUserInstance: user={1} - EXIT!", this.getClass().getSimpleName(), user));
-
                // Return it
-               return localUser;
+               return user;
        }
 
        @Override
@@ -422,23 +670,22 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                // Is all data set?
                if (this.getUserName() == null) {
                        // Throw NPE
-                       throw new NullPointerException("recruiterName is null"); //NOI18N
+                       throw new NullPointerException("userName is null"); //NOI18N
                } else if (this.getUserName().isEmpty()) {
                        // Is empty
-                       throw new IllegalStateException("recruiterName is empty."); //NOI18N
+                       throw new IllegalStateException("userName is empty."); //NOI18N
                }
 
-               // Create new recruiter instance
-               User recruiter = new LoginUser();
+               // Create new user instance
+               User user = new LoginUser();
 
                // Update all data ...
-               recruiter.setUserName(this.getUserName());
+               user.setUserName(this.getUserName());
 
                // Trace message
-               //* NOISY-DEBUG */ System.out.println(MessageFormat.format("{0}.createUserLogin: recruiter={1} - EXIT!", this.getClass().getSimpleName(), recruiter));
-
+               //* NOISY-DEBUG */ System.out.println(MessageFormat.format("{0}.createUserLogin: user={1} - EXIT!", this.getClass().getSimpleName(), user));
                // Return the new instance
-               return recruiter;
+               return user;
        }
 
        @Override
@@ -453,6 +700,9 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                } else if (!this.userLoginController.ifCurrentPasswordMatches()) {
                        // Password not matching
                        throw new FaceletException(new UserPasswordMismatchException(this.userLoginController.getLoggedInUser()));
+               } else if (!this.featureController.isFeatureEnabled("change_user_personal_data")) { //NOI18N
+                       // Editing is not allowed
+                       throw new IllegalStateException("User tried to edit personal data."); //NOI18N
                }
 
                // Get user instance
@@ -476,28 +726,44 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                User updatedUser = this.userBean.updateUserPersonalData(user);
 
                // Fire event
-               this.updatedPersonalDataEvent.fire(new UserUpdatedPersonalDataEvent(updatedUser));
+               this.updatedPersonalDataEvent.fire(new UpdatedUserPersonalDataEvent(updatedUser));
 
                // All fine
-               return "user_data_saved"; //NOI18N
+               return "user_contact_data_saved"; //NOI18N
        }
 
-       @Override
+       /**
+        * Getter for user id
+        * <p>
+        * @return User id
+        */
        public Long getUserId () {
                return this.userId;
        }
 
-       @Override
+       /**
+        * Setter for user id
+        * <p>
+        * @param userId User id
+        */
        public void setUserId (final Long userId) {
                this.userId = userId;
        }
 
-       @Override
+       /**
+        * Getter for user name
+        * <p>
+        * @return User name
+        */
        public String getUserName () {
                return this.userName;
        }
 
-       @Override
+       /**
+        * Setter for user name
+        * <p>
+        * @param userName User name
+        */
        public void setUserName (final String userName) {
                this.userName = userName;
        }
@@ -507,34 +773,57 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                return this.userPassword;
        }
 
-       @Override
+       /**
+        * Setter for clear-text user password
+        * <p>
+        * @param userPassword Clear-text user password
+        */
        public void setUserPassword (final String userPassword) {
                this.userPassword = userPassword;
        }
 
-       @Override
+       /**
+        * Getter for clear-text user password repeated
+        * <p>
+        * @return Clear-text user password repeated
+        */
        public String getUserPasswordRepeat () {
                return this.userPasswordRepeat;
        }
 
-       @Override
+       /**
+        * Setter for clear-text user password repeated
+        * <p>
+        * @param userPasswordRepeat Clear-text user password repeated
+        */
        public void setUserPasswordRepeat (final String userPasswordRepeat) {
                this.userPasswordRepeat = userPasswordRepeat;
        }
 
-       @Override
+       /**
+        * Getter for user profile mode
+        * <p>
+        * @return User profile mode
+        */
        public ProfileMode getUserProfileMode () {
                return this.userProfileMode;
        }
 
-       @Override
+       /**
+        * Setter for user profile mode
+        * <p>
+        * @param userProfileMode User profile mode
+        */
        public void setUserProfileMode (final ProfileMode userProfileMode) {
                this.userProfileMode = userProfileMode;
        }
 
        @Override
-       public boolean hasUsers () {
-               return (!this.allUsers().isEmpty());
+       public boolean ifBothPasswordsEmptyAllowed () {
+               // Check feature first
+               return ((this.featureController.isFeatureEnabled("allow_user_registration_empty_password")) && //NOI18N
+                               ((this.getUserPassword() == null) || (this.getUserPassword().isEmpty())) &&
+                               ((this.getUserPasswordRepeat() == null) || (this.getUserPasswordRepeat().isEmpty())));
        }
 
        /**
@@ -556,40 +845,6 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                        // Initialize user list
                        this.visibleUserList = this.userBean.allPublicUsers();
                }
-
-               // Get all users
-               List<User> allUsers = this.allUsers();
-
-               // Get all contacts
-               List<Contact> allContacts = this.contactBean.getAllContacts();
-
-               // Get iterator
-               Iterator<Contact> iterator = allContacts.iterator();
-
-               // Loop through it
-               while (iterator.hasNext()) {
-                       // Get next element
-                       Contact next = iterator.next();
-
-                       // Get iterator
-                       Iterator<User> userIterator = allUsers.iterator();
-
-                       // Loop through all users
-                       while (userIterator.hasNext()) {
-                               // Get user instance
-                               User nextUser = userIterator.next();
-
-                               // Is contact same?
-                               if (Objects.equals(next, nextUser.getUserContact())) {
-                                       // Found same
-                                       iterator.remove();
-                                       break;
-                               }
-                       }
-               }
-
-               // Set contact list
-               this.selectableContacts = allContacts;
        }
 
        @Override
@@ -635,16 +890,16 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                String contextParameter = FacesContext.getCurrentInstance().getExternalContext().getInitParameter("is_public_profile_enabled"); //NOI18N
 
                // Is it set?
-               boolean isPublicUserProfileEnabled = ((contextParameter instanceof String) && (contextParameter.toLowerCase().equals("true"))); //NOI18N
+               boolean isEnabled = ((contextParameter instanceof String) && (contextParameter.toLowerCase().equals("true"))); //NOI18N
 
                // This requires user names being enabled, too.
-               if ((isPublicUserProfileEnabled) && (!this.isUserNameRequired())) {
+               if ((isEnabled) && (!this.isUserNameRequired())) {
                        // Not valid state, users must be able to modify their profile, especially when it is public
                        throw new IllegalStateException("Public user profiles are enabled but user name requirement is disabled, this is not possible."); //NOI18N
                }
 
                // Return value
-               return isPublicUserProfileEnabled;
+               return isEnabled;
        }
 
        @Override
@@ -656,7 +911,7 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
 
        @Override
        public boolean isRequiredPersonalDataSet () {
-               if (this.registerController.isMultiplePageEnabled()) {
+               if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
                        // Multiple registration page
                        return this.contactController.isRequiredPersonalDataSet();
                } else {
@@ -687,13 +942,13 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
        @Override
        public boolean isUserNameRequired () {
                // Get context parameter
-               String contextParameter = FacesContext.getCurrentInstance().getExternalContext().getInitParameter("is_user_name_required"); //NOI18N
+               String contextParameter = FacesContext.getCurrentInstance().getExternalContext().getInitParameter("is_user_login_require_user_name"); //NOI18N
 
                // Is it set?
-               boolean isUserNameRequired = ((contextParameter instanceof String) && (contextParameter.toLowerCase().equals("true"))); //NOI18N
+               boolean isRequired = ((contextParameter instanceof String) && (contextParameter.toLowerCase().equals("true"))); //NOI18N
 
                // Return value
-               return isUserNameRequired;
+               return isRequired;
        }
 
        @Override
@@ -701,6 +956,52 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                return ((this.visibleUserList instanceof List) && (this.visibleUserList.size() > 0));
        }
 
+       @Override
+       public User lookupUserByEmailAddress (final String emailAddress) throws UserEmailAddressNotFoundException {
+               // Parameter must be valid
+               if (null == emailAddress) {
+                       // Throw NPE
+                       throw new NullPointerException("emailAddress is null"); //NOI18N
+               } else if (emailAddress.isEmpty()) {
+                       // Not valid
+                       throw new IllegalArgumentException("emailAddress is empty"); //NOI18N
+               }
+
+               // Init variable
+               User user = null;
+
+               // Try to lookup it in visible user list
+               for (final Iterator<User> iterator = this.userList.iterator(); iterator.hasNext();) {
+                       // Get next user
+                       User next = iterator.next();
+
+                       // Contact should be set
+                       if (next.getUserContact() == null) {
+                               // Contact is null
+                               throw new NullPointerException(MessageFormat.format("next.userContact is null for user id {0}", next.getUserId())); //NOI18N
+                       } else if (next.getUserContact().getContactEmailAddress() == null) {
+                               // Email address should be set
+                               throw new NullPointerException(MessageFormat.format("next.userContact.contactEmailAddress is null for user id {0}", next.getUserId())); //NOI18N
+                       }
+
+                       // Is the email address found?
+                       if (Objects.equals(next.getUserContact().getContactEmailAddress(), emailAddress)) {
+                               // Copy to other variable
+                               user = next;
+                               break;
+                       }
+               }
+
+               // Is it still null?
+               if (null == user) {
+                       // Not visible for the current user
+                       throw new UserEmailAddressNotFoundException(emailAddress);
+               }
+
+               // Return it
+               return user;
+       }
+
        @Override
        public User lookupUserById (final Long userId) throws UserNotFoundException {
                // Parameter must be valid
@@ -738,11 +1039,6 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                return user;
        }
 
-       @Override
-       public List<Contact> selectableContacts () {
-               return Collections.unmodifiableList(this.selectableContacts);
-       }
-
        /**
         * Adds user's name to bean's internal list. It also updates the public user
         * list if the user has decided to have a public account,
@@ -754,9 +1050,6 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                if (this.userNameList.contains(user.getUserName())) {
                        // Abort here
                        throw new IllegalArgumentException(MessageFormat.format("User name {0} already added.", user.getUserName())); //NOI18N
-               } else if (this.contactController.isEmailAddressRegistered(user.getUserContact())) {
-                       // Already added
-                       throw new IllegalArgumentException(MessageFormat.format("Email address {0} already added.", user.getUserContact().getContactEmailAddress())); //NOI18N
                }
 
                // Add user name
@@ -773,7 +1066,24 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                this.setUserProfileMode(null);
 
                // - other data
+               this.clearUserName();
+               this.clearUserPasswords();
+               this.setLocale(null);
+       }
+
+       /**
+        * Clears user name
+        */
+       private void clearUserName () {
+               // Clear it
                this.setUserName(null);
+       }
+
+       /**
+        * Clears both user passwords
+        */
+       private void clearUserPasswords () {
+               // Clear both
                this.setUserPassword(null);
                this.setUserPasswordRepeat(null);
        }
@@ -799,6 +1109,50 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                this.setUserProfileMode(user.getUserProfileMode());
        }
 
+       /**
+        * Getter for locale instance
+        * <p>
+        * @return Locale instance
+        */
+       private Locale getLocale () {
+               return this.locale;
+       }
+
+       /**
+        * Setter for locale instance
+        * <p>
+        * @param locale Locale instance
+        */
+       private void setLocale (final Locale locale) {
+               this.locale = locale;
+       }
+
+       /**
+        * Removes user from all lists
+        * <p>
+        * @param user User to remove
+        */
+       private void removeFromList (final User user) {
+               // The user should be valid
+               if (null == user) {
+                       // Throw NPE
+                       throw new NullPointerException("user is null"); //NOI18N
+               } else if (user.getUserId() == null) {
+                       // ... again NPE
+                       throw new NullPointerException("user.userId is null"); //NOI18N
+               } else if (user.getUserId() < 1) {
+                       // Invalid id
+                       throw new IllegalArgumentException(MessageFormat.format("user.userId={0} is invalid", user.getUserId())); //NOI18N
+               }
+
+               // Remove it from lists
+               this.userList.remove(user);
+               this.visibleUserList.remove(user);
+
+               // Remove name from list
+               this.userNameList.remove(user.getUserName());
+       }
+
        /**
         * Updates list with given user instance
         * <p>
@@ -815,25 +1169,34 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs
                } else if (user.getUserId() < 1) {
                        // Invalid id
                        throw new IllegalArgumentException(MessageFormat.format("user.userId={0} is invalid", user.getUserId())); //NOI18N
+               } else if (user.getUserContact() == null) {
+                       // Throw again ...
+                       throw new NullPointerException("user.userContact is null"); //NOI18N
+               } else if (user.getUserContact().getContactId() == null) {
+                       // Throw again ...
+                       throw new NullPointerException("user.userContact.contactId is null"); //NOI18N
+               } else if (user.getUserContact().getContactId() < 1) {
+                       // Throw again ...
+                       throw new NullPointerException(MessageFormat.format("user.userContact.contactId={0} is invalid.", user.getUserContact().getContactId())); //NOI18N
                }
 
-               // Get iterator
+               // Get iterator from list
                Iterator<User> iterator = this.userList.iterator();
 
-               // Look whole list
+               // "Walk" through all entries
                while (iterator.hasNext()) {
                        // Get next element
                        User next = iterator.next();
 
-                       // Is the same user id?
+                       // Is user id number the same?
                        if (Objects.equals(user.getUserId(), next.getUserId())) {
-                               // Found it, so remove it
+                               // Found entry, so remove it and abort
                                this.userList.remove(next);
                                break;
                        }
                }
 
-               // Re-add item
+               // Re-add user
                this.userList.add(user);
        }