/*
* (c) 2008- RANDI2 Core Development Team
*
* This file is part of RANDI2.
*
* RANDI2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* RANDI2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* RANDI2. If not, see <http://www.gnu.org/licenses/>.
*/
package de.randi2.jsf.controllerBeans;
import java.io.IOException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import lombok.Getter;
import lombok.Setter;
import org.apache.log4j.Logger;
import org.springframework.security.core.context.SecurityContextHolder;
import com.icesoft.faces.component.ext.HtmlInputText;
import de.randi2.jsf.backingBeans.RegisterPage;
import de.randi2.jsf.converters.LoginConverter;
import de.randi2.jsf.converters.RoleConverter;
import de.randi2.jsf.exceptions.RegistrationException;
import de.randi2.jsf.supportBeans.PermissionVerifier;
import de.randi2.jsf.supportBeans.Popups;
import de.randi2.jsf.supportBeans.Randi2;
import de.randi2.model.AbstractDomainObject;
import de.randi2.model.Login;
import de.randi2.model.Person;
import de.randi2.model.Role;
import de.randi2.model.TrialSite;
import de.randi2.services.TrialSiteService;
import de.randi2.services.UserService;
import de.randi2.utility.logging.LogEntry;
import de.randi2.utility.logging.LogEntry.ActionType;
import de.randi2.utility.logging.LogService;
/**
* <p>
* This class takes care of login objects and contains all UI-specific methods
* needed for working with login and person objects.
* </p>
*
* @author Lukasz Plotnicki <lplotni@users.sourceforge.net>
*/
@ManagedBean(name = "loginHandler")
@SessionScoped
public class LoginHandler extends AbstractHandler<Login> {
/*
* Services classes to work with - provided via JSF/Spring brige.
*/
@ManagedProperty(value = "#{userService}")
@Setter
private UserService userService;
@ManagedProperty(value = "#{logService}")
@Setter
private LogService logService;
@ManagedProperty(value = "#{trialSiteService}")
@Setter
private TrialSiteService siteService;
/*
* Reference to the application popup logic.
*/
@ManagedProperty(value = "#{popups}")
@Setter
private Popups popups;
/*
* Current signed in user.
*/
@Setter
private Login loggedInUser = null;
private LoginConverter loginConverter;
public LoginConverter getLoginConverter() {
if (loginConverter == null)
loginConverter = new LoginConverter(userService);
return loginConverter;
}
/*
* Current (chosen) locale of the UI.
*/
@Setter
private Locale chosenLocale = null;
/*
* newUser - object for the self registration process tsPasswort - trail
* site password for the self registration process
*/
private Login newUser = null;
@Getter
@Setter
private String tsPassword = null;
private List<SelectItem> trialSites;
public List<SelectItem> getTrialSites() {
if (trialSites == null) {
trialSites = new ArrayList<SelectItem>();
trialSites.add(new SelectItem(null, "please select"));
for (TrialSite site : siteService.getAll()) {
trialSites.add(new SelectItem(site, site.getName()));
}
}
return trialSites;
}
@Getter
@Setter
private TrialSite selectedTrialSite;
private List<SelectItem> roles;
public List<SelectItem> getRoles() {
if (roles == null) {
roles = new ArrayList<SelectItem>();
roles.add(new SelectItem(null, "please select"));
for (Role r : userService.getRolesToAssign(loggedInUser)) {
roles.add(new SelectItem(r, getRoleConverter().getAsString(
null, null, r)));
}
}
return roles;
}
@Getter
@Setter
private Role selectedRole;
private RoleConverter roleConverter;
public RoleConverter getRoleConverter() {
if (roleConverter == null)
roleConverter = new RoleConverter(userService, getChosenLocale());
return roleConverter;
}
/*
* UI logic
*/
/**
* ActionListener for the "add role" event.
*
* @param event
*/
public void addRole(ActionEvent event) {
currentObject.addRole(selectedRole);
}
/**
* ActionListener for the "remove role" event.
*
* @param event
*/
public void removeRole(ActionEvent event) {
assert (userService != null);
Role tRole = (Role) (((UIComponent) event.getComponent().getChildren()
.get(0)).getValueExpression("value").getValue(FacesContext
.getCurrentInstance().getELContext()));
currentObject.removeRole(tRole);
}
/**
* Action Method for the "change password" action.
*
* @return
*/
public String changePassword() {
this.saveObject();
popups.hideChangePasswordPopup();
return Randi2.SUCCESS;
}
public String changeTrialSite() {
if (selectedTrialSite != null) {
popups.hideChangeTrialSitePopup();
try {
siteService.changePersonTrialSite(selectedTrialSite,
currentObject.getPerson());
return Randi2.SUCCESS;
} catch (Exception exp) {
Randi2.showMessage(exp);
return Randi2.ERROR;
} finally {
if (currentObject.getId() == loggedInUser.getId())
loggedInUser = currentObject;
refresh();
}
}
return Randi2.ERROR;
}
/*
* (non-Javadoc)
*
* @see de.randi2.jsf.handlers.AbstractHandler#saveObject()
*/
@Override
public String saveObject() {
assert (currentObject != null);
try {
currentObject = userService.update(currentObject);
// Making the pop up visible
popups.setUserSavedPVisible(true);
return Randi2.SUCCESS;
} catch (Exception exp) {
Randi2.showMessage(exp);
return Randi2.ERROR;
} finally {
if (currentObject.getId() == loggedInUser.getId())
loggedInUser = currentObject;
refresh();
}
}
/**
* This method is responsible for the users registration.
*
* @return Randi2.SUCCESS normally. Randi2.ERROR in case of an error.
*/
public String registerUser() {
/*
* TODO We could try to move the newUser and tsPassword object as well
* as a part of this functionality into the RegisterPage bean.
*/
try {
if (creatingMode) {
// A new user was created by another logged in user
newUser = currentObject;
} else {
// Normal self-registration - trial site password check!
assert (newUser != null);
try {
if (!siteService.authorize(selectedTrialSite, tsPassword)) {
throw new RegistrationException(
RegistrationException.PASSWORD_ERROR);
}
} catch (NullPointerException exp1) {
// No trial site selected
throw new RegistrationException(
RegistrationException.TRIAL_SITE_ERROR);
}
}
/* Setting the data in the new object */
newUser.setPrefLocale(getChosenLocale());
newUser.setUsername(newUser.getPerson().getEmail());
/* The new object will be saved */
if (creatingMode) {
userService.create(newUser, selectedTrialSite);
} else {
userService.register(newUser, selectedTrialSite);
}
// Making the successPopup visible (NORMAL REGISTRATION)
if (!creatingMode) {
((RegisterPage) FacesContext
.getCurrentInstance()
.getApplication()
.getELResolver()
.getValue(
FacesContext.getCurrentInstance()
.getELContext(), null, "registerPage"))
.setRegPvisible(true);
// Reseting the objects used for the registration process
this.cleanUp();
// Invalidate Reg-Session
invalidateSession();
}
// Making the popup visible (CREATING AN USER BY ANOTHER USER)
if (creatingMode) {
popups.setUserSavedPVisible(true);
}
return Randi2.SUCCESS;
} catch (ConstraintViolationException exp) {
for (ConstraintViolation<?> v : exp.getConstraintViolations()) {
Randi2.showMessage(v.getPropertyPath() + " : " + v.getMessage());
}
return Randi2.ERROR;
} catch (Exception e) {
Randi2.showMessage(e);
return Randi2.ERROR;
}
}
/**
* This method saves the current loggedInUser-object and log it out.
*
* @return Randi2.SUCCESS
*/
public String logoutUser() {
loggedInUser = userService.update(loggedInUser);
invalidateSession();
logService.logChange(ActionType.LOGOUT, loggedInUser.getUsername(),
loggedInUser);
return Randi2.SUCCESS;
}
/**
* This method clean all references within the LoginHandler-object.
*/
public void cleanUp() {
tsPassword = null;
newUser = null;
trialSites = null;
}
/*
* (non-Javadoc)
*
* @see de.randi2.jsf.handlers.AbstractHandler#refreshShowedObject()
*/
@Override
public String refreshShowedObject() {
if (currentObject.getId() == AbstractDomainObject.NOT_YET_SAVED_ID) {
currentObject = null;
newUser = null;
currentObject = getNewUser();
} else {
currentObject = userService.getObject(currentObject.getId());
}
selectedTrialSite = null;
refresh();
return Randi2.SUCCESS;
}
public void setUSEnglish(ActionEvent event) {
this.loggedInUser.setPrefLocale(Locale.US);
this.setChosenLocale(Locale.US);
}
public void setDEGerman(ActionEvent event) {
this.loggedInUser.setPrefLocale(Locale.GERMANY);
this.setChosenLocale(Locale.GERMANY);
}
/*
* GET & SET Methods
*/
/**
* Provides the current logged in user.
*
* @return
*/
public Login getLoggedInUser() {
if (loggedInUser == null) {
try {
loggedInUser = (Login) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
/*
* Reloading the user from the database to ensure that the
* object is attached to the correct session
*/
// loggedInUser = userService.getObject(loggedInUser.getId());
loggedInUser.setLastLoggedIn(new GregorianCalendar());
} catch (NullPointerException exp) {
Logger.getLogger(this.getClass()).debug("NPE", exp);
}
}
return this.loggedInUser;
}
/**
* This method provide the locale chosen by the logged user. If the user
* didn't choose anyone, but his standard browser-locale is supported, then
* it will be provided. Otherwise the applications default locale will be
* used. setTri
*
* @return locale for the loged in user
*/
public Locale getChosenLocale() {
if (this.loggedInUser != null) {
if (this.loggedInUser.getPrefLocale() != null) {
this.chosenLocale = this.loggedInUser.getPrefLocale();
}
} else {
this.chosenLocale = FacesContext.getCurrentInstance()
.getExternalContext().getRequestLocale();
Iterator<Locale> supportedLocales = FacesContext
.getCurrentInstance().getApplication()
.getSupportedLocales();
while (supportedLocales.hasNext()) {
if (supportedLocales.next().equals(this.chosenLocale))
return this.chosenLocale;
}
this.chosenLocale = FacesContext.getCurrentInstance()
.getApplication().getDefaultLocale();
}
return this.chosenLocale;
}
/**
* This method specifies if the object that is currently showed in the UI,
* is editable or not.
*
* @return
*/
public boolean isEditable() {
PermissionVerifier permissionVerifier = ((PermissionVerifier) FacesContext
.getCurrentInstance()
.getApplication()
.getELResolver()
.getValue(FacesContext.getCurrentInstance().getELContext(),
null, "permissionVerifier"));
if (currentObject.equals(this.loggedInUser)
|| permissionVerifier.isAllowedEditUser(currentObject)) {
editable = true;
} else {
editable = creatingMode;
}
return editable;
}
/**
* This method provides a Login object for the registration and user
* creation process.
*
* @return A Login object, which represents the new user.
*/
public Login getNewUser() {
if (newUser == null) { // Starting the registration process
assert (userService != null);
if (creatingMode) { // new user created from another user
newUser = new Login();
newUser.setPerson(new Person());
} else { // self-registration process
newUser = userService.prepareInvestigator();
}
}
return newUser;
}
/**
* Use this method to invalidate the current HTTPSession and show the
* loginPage
*/
public void invalidateSession() {
final HttpSession session = (HttpSession) FacesContext
.getCurrentInstance().getExternalContext().getSession(false);
session.setAttribute(Randi2.RANDI2_END, "The end");
try {
FacesContext
.getCurrentInstance()
.getExternalContext()
.redirect(
FacesContext.getCurrentInstance()
.getExternalContext()
.getRequestContextPath()
+ Randi2.SECURE_LOGOUT_PATH);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Method for initial assistant creation
*
* @param event
*/
public void createAssistant(ActionEvent event) {
if (currentObject != null)
currentObject.getPerson().setAssistant(new Person());
}
/**
* Provides the audit log entries for the showed object.
*
* @return
*/
public List<LogEntry> getLogEntries() {
return logService.getLogEntries(currentObject.getUsername());
}
/*
* (non-Javadoc)
*
* @see de.randi2.jsf.controllerBeans.AbstractHandler#createPlainObject()
*/
@Override
protected Login createPlainObject() {
Login l = new Login();
l.setPerson(new Person());
return l;
}
public TrialSite getCurrentUsersTrialSite() {
return siteService.getTrialSiteFromPerson(currentObject.getPerson());
}
public void passwordChangeListener(ValueChangeEvent event) {
if (!event.getNewValue().equals(event.getOldValue())) {
HtmlInputText confirmationPasswordInput = (HtmlInputText) event
.getComponent().getParent().getParent()
.findComponent("pConfirmation");
confirmationPasswordInput.setValue("");
}
}
}