edu.harvard.med.screensaver.ui.users.UserViewer.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.med.screensaver.ui.users.UserViewer.java

Source

// $HeadURL$
// $Id$
//
// Copyright  2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.

package edu.harvard.med.screensaver.ui.users;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

import org.apache.log4j.Logger;
import org.joda.time.LocalDate;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;

import edu.harvard.med.iccbl.screensaver.IccblScreensaverConstants;
import edu.harvard.med.iccbl.screensaver.policy.DataSharingLevelMapper;
import edu.harvard.med.screensaver.ScreensaverConstants;
import edu.harvard.med.screensaver.db.Criterion;
import edu.harvard.med.screensaver.db.Criterion.Operator;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.UsersDAO;
import edu.harvard.med.screensaver.model.AttachedFile;
import edu.harvard.med.screensaver.model.AttachedFileType;
import edu.harvard.med.screensaver.model.activities.Activity;
import edu.harvard.med.screensaver.model.activities.ServiceActivity;
import edu.harvard.med.screensaver.model.screens.Screen;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.AffiliationCategory;
import edu.harvard.med.screensaver.model.users.ChecklistItemEvent;
import edu.harvard.med.screensaver.model.users.ChecklistItemGroup;
import edu.harvard.med.screensaver.model.users.FacilityUsageRole;
import edu.harvard.med.screensaver.model.users.Gender;
import edu.harvard.med.screensaver.model.users.Lab;
import edu.harvard.med.screensaver.model.users.LabAffiliation;
import edu.harvard.med.screensaver.model.users.LabHead;
import edu.harvard.med.screensaver.model.users.ScreeningRoomUser;
import edu.harvard.med.screensaver.model.users.ScreeningRoomUserClassification;
import edu.harvard.med.screensaver.model.users.ScreensaverUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUserComparator;
import edu.harvard.med.screensaver.model.users.ScreensaverUserRole;
import edu.harvard.med.screensaver.model.users.UserAttachedFileType;
import edu.harvard.med.screensaver.service.OperationRestrictedException;
import edu.harvard.med.screensaver.service.screens.ScreenGenerator;
import edu.harvard.med.screensaver.ui.activities.ActivitySearchResults;
import edu.harvard.med.screensaver.ui.activities.ActivityViewer;
import edu.harvard.med.screensaver.ui.arch.util.AttachedFiles;
import edu.harvard.med.screensaver.ui.arch.util.ChecklistItems;
import edu.harvard.med.screensaver.ui.arch.util.JSFUtils;
import edu.harvard.med.screensaver.ui.arch.util.UISelectOneBean;
import edu.harvard.med.screensaver.ui.arch.util.UISelectOneEntityBean;
import edu.harvard.med.screensaver.ui.arch.view.EditResult;
import edu.harvard.med.screensaver.ui.arch.view.SearchResultContextEditableEntityViewerBackingBean;
import edu.harvard.med.screensaver.ui.arch.view.aspects.UICommand;
import edu.harvard.med.screensaver.ui.screens.ScreenDetailViewer;
import edu.harvard.med.screensaver.ui.screens.ScreenSearchResults;
import edu.harvard.med.screensaver.util.DevelopmentException;
import edu.harvard.med.screensaver.util.NullSafeComparator;
import edu.harvard.med.screensaver.util.NullSafeUtils;
import edu.harvard.med.screensaver.util.StringUtils;

/**
 * User Viewer backing bean.
 *
 * @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
 */
public class UserViewer
        extends SearchResultContextEditableEntityViewerBackingBean<ScreeningRoomUser, ScreeningRoomUser> {
    // static members

    private static Logger log = Logger.getLogger(UserViewer.class);
    private static final Comparator<ScreensaverUserRole> USER_ROLE_COMPARATOR = new Comparator<ScreensaverUserRole>() {
        public int compare(ScreensaverUserRole r1, ScreensaverUserRole r2) {
            return ((Integer) r1.ordinal()).compareTo(r2.ordinal());
        }
    };
    private static final AffiliationCategory DEFAULT_NEW_LAB_AFFILIATION_CATEGORY = AffiliationCategory.HMS;
    /** checklist item groups to show in user interface, per requirements */
    private static final List<ChecklistItemGroup> CHECKLIST_ITEM_GROUPS = Lists
            .newArrayList(ChecklistItemGroup.values());
    static {
        CHECKLIST_ITEM_GROUPS.remove(ChecklistItemGroup.LEGACY);
    }

    // instance data members

    private ScreenDetailViewer _screenDetailViewer;
    private UsersDAO _usersDao;
    private ScreenGenerator _screenGenerator;
    private ScreenSearchResults _screensBrowser;
    private AttachedFiles _attachedFiles;
    private ChecklistItems _checklistItems;

    private DataModel _userRolesDataModel;
    private UISelectOneBean<ScreensaverUserRole> _newUserRole;
    private UISelectOneEntityBean<LabHead> _labName;
    private UISelectOneEntityBean<LabAffiliation> _labAffiliation;
    private LabAffiliation _newLabAffiliation;
    private HashMap<ScreenType, DataModel> _screensDataModel;
    private DataModel _labMembersDataModel;
    private DataModel _screenAssociatesDataModel;
    private Set<ScreensaverUserRole> _lastPrimaryRoles;
    private DataModel _facilityUsageRolesDataModel;
    private UISelectOneBean<FacilityUsageRole> _newFacilityUsageRole;
    private String _newPassword1;
    private String _newPassword2;
    private ActivityViewer _activityViewer;
    private ActivitySearchResults _activitiesBrowser;

    private UISelectOneBean<Gender> _gender;

    // constructors

    /**
     * @motivation for CGLIB2
     */
    protected UserViewer() {
    }

    public UserViewer(UserViewer userViewerProxy, ScreenDetailViewer screenDetailViewer,
            ActivityViewer activityViewer, ActivitySearchResults activitiesBrowser, GenericEntityDAO dao,
            UsersDAO usersDao, ScreenGenerator screenGenerator, UserSearchResults userSearchResults,
            ScreenSearchResults screensBrowser, AttachedFiles attachedFiles, ChecklistItems checklistItems) {
        super(userViewerProxy, ScreeningRoomUser.class, BROWSE_SCREENERS, VIEW_USER, dao, userSearchResults);
        _screenDetailViewer = screenDetailViewer;
        _activityViewer = activityViewer;
        _activitiesBrowser = activitiesBrowser;
        _usersDao = usersDao;
        _screenGenerator = screenGenerator;
        _screensBrowser = screensBrowser;
        _attachedFiles = attachedFiles;
        _checklistItems = checklistItems;
        getIsPanelCollapsedMap().put("labMembers", true);
        getIsPanelCollapsedMap().put("screenAssociates", true);
        getIsPanelCollapsedMap().put("smallMoleculeScreens", false);
        getIsPanelCollapsedMap().put("rnaiScreens", false);
        getIsPanelCollapsedMap().put("screens", false);
        getIsPanelCollapsedMap().put("userActivities", false);
    }

    public boolean isManageAuthenticationCredentialsFeatureEnabled() {
        return getApplicationProperties().isFeatureEnabled("manage_authentication_credentials");
    }

    /**
     * @return true if the logged in user is the same as the user being shown by the user viewer
     *
     */
    public boolean isMe() {
        return getEntity().equals(getScreensaverUser());
    }

    public boolean isScreeningRoomUserViewMode() {
        return getScreeningRoomUser() != null;
    }

    public boolean isLabHeadViewMode() {
        return getLabHead() != null;
    }

    public ScreeningRoomUser getScreeningRoomUser() {
        if (getEntity() instanceof ScreeningRoomUser) {
            return (ScreeningRoomUser) getEntity();
        }
        return null;
    }

    public LabHead getLabHead() {
        if (getEntity() instanceof LabHead) {
            return (LabHead) getEntity();
        }
        return null;
    }

    @Override
    protected void initializeEntity(ScreeningRoomUser user) {
        getDao().need(user, ScreeningRoomUser.roles);
        getDao().need(user, ScreensaverUser.updateActivities);
        getDao().need(user, ScreensaverUser.activitiesPerformed.to(Activity.performedBy));
        getDao().need(user, ScreeningRoomUser.serviceActivities.to(Activity.performedBy));
        // note: no cross-product problem with dual labMembers associations, since only one will have size > 0
        getDao().need(user, ScreeningRoomUser.LabHead.to(LabHead.labAffiliation));
        getDao().need(user, ScreeningRoomUser.LabHead.to(LabHead.labMembers));
        if (user instanceof LabHead) {
            getDao().need((LabHead) user, LabHead.labAffiliation);
            getDao().need((LabHead) user, LabHead.labMembers);
        }
        // for UserAgreementUpdater
        getDao().need(user, ScreeningRoomUser.LabHead.to(ScreensaverUser.roles));
        getDao().need(user, ScreeningRoomUser.screensLed.to(Screen.statusItems));
        getDao().need(user, ScreeningRoomUser.screensLed.to(Screen.labHead));
        getDao().need(user, ScreeningRoomUser.screensLed.to(Screen.leadScreener));
        getDao().need(user, ScreeningRoomUser.screensLed.to(Screen.collaborators));
        getDao().need(user, ScreeningRoomUser.screensLed.to(Screen.labActivities));
        getDao().need(user, ScreeningRoomUser.screensCollaborated.to(Screen.statusItems));
        getDao().need(user, ScreeningRoomUser.screensCollaborated.to(Screen.labHead));
        getDao().need(user, ScreeningRoomUser.screensCollaborated.to(Screen.leadScreener));
        getDao().need(user, ScreeningRoomUser.screensCollaborated.to(Screen.collaborators));
        getDao().need(user, ScreeningRoomUser.screensCollaborated.to(Screen.labActivities));
        if (user instanceof LabHead) {
            getDao().need((LabHead) user, LabHead.screensHeaded.to(Screen.statusItems));
            getDao().need((LabHead) user, LabHead.screensHeaded.to(Screen.labActivities));
            getDao().need((LabHead) user, LabHead.screensHeaded.to(Screen.labHead));
            getDao().need((LabHead) user, LabHead.screensHeaded.to(Screen.leadScreener));
            getDao().need((LabHead) user, LabHead.screensHeaded.to(Screen.collaborators));
        }

        getDao().need(user, ScreeningRoomUser.checklistItemEvents.to(ChecklistItemEvent.checklistItem));
        getDao().need(user, ScreeningRoomUser.checklistItemEvents.to(ChecklistItemEvent.screeningRoomUser));
        getDao().need(user, ScreeningRoomUser.checklistItemEvents.to(ChecklistItemEvent.createdBy));
        getDao().need(user, ScreeningRoomUser.attachedFiles.to(AttachedFile.fileType));
        getDao().need(user, ScreeningRoomUser.facilityUsageRoles);
    }

    @Override
    protected void initializeViewer(ScreeningRoomUser user) {
        if (!!!user.isTransient()) {
            warnAdminOnMismatchedLabMemberDataSharingLevel(user, ScreenType.SMALL_MOLECULE);
            warnAdminOnMismatchedLabMemberDataSharingLevel(user, ScreenType.RNAI);
            warnAdminOnLabHeadScreensTooRestrictive(user);
        }

        _userRolesDataModel = null;
        _facilityUsageRolesDataModel = null;
        _newFacilityUsageRole = null;
        _newUserRole = null;
        _labName = null;
        _labAffiliation = null;
        _newLabAffiliation = null;
        _screensDataModel = null;
        _labMembersDataModel = null;
        _screenAssociatesDataModel = null;
        _attachedFiles.initialize(user,
                Sets.<AttachedFileType>newTreeSet(getDao().findAllEntitiesOfType(UserAttachedFileType.class)),
                null);
        _checklistItems.setEntity(user);
        _checklistItems.setChecklistItemGroups(CHECKLIST_ITEM_GROUPS);
        _lastPrimaryRoles = user.getPrimaryScreensaverUserRoles();
        _newPassword1 = null;
        _newPassword2 = null;
        _gender = null;
    }

    @Override
    protected boolean validateEntity(ScreeningRoomUser entity) {
        boolean isNewPasswordDefined = !NullSafeUtils.toString(_newPassword1, "").isEmpty()
                || !NullSafeUtils.toString(_newPassword2, "").isEmpty();
        if (isNewPasswordDefined && !NullSafeUtils.nullSafeEquals(_newPassword1, _newPassword2)) {
            showMessage("users.passwordsDoNotMatch");
            return false;
        }
        boolean isLoginIdDefined = !StringUtils.isEmpty(entity.getLoginId());
        boolean isExistingPasswordDefined = !NullSafeUtils.toString(entity.getDigestedPassword(), "").isEmpty();
        if (isNewPasswordDefined && !isLoginIdDefined
                || isLoginIdDefined && !isExistingPasswordDefined && !isNewPasswordDefined) {
            showMessage("users.loginIdAndPasswordRequired");
            return false;
        }
        return true;
    }

    @Override
    public void updateEntityProperties(ScreeningRoomUser user) {
        if (user.isHeadOfLab()) {
            user.getLab().setLabAffiliation(getLabAffiliation().getSelection());
        } else {
            Lab lab = getLabName().getSelection() == null ? null : getLabName().getSelection().getLab();
            user.setLab(lab);
        }
        if (StringUtils.isEmpty(user.getLoginId())) {
            user.setDigestedPassword(null);
        } else if (!NullSafeUtils.toString(_newPassword1, "").isEmpty()) {
            user.updateScreensaverPassword(_newPassword1);
        }
    }

    protected void recordUpdateActivity() {
        Set<ScreensaverUserRole> rolesAdded = Sets.difference(getEntity().getPrimaryScreensaverUserRoles(),
                _lastPrimaryRoles);
        if (!!!rolesAdded.isEmpty()) {
            recordUpdateActivity("primary roles added: " + Joiner.on(", ")
                    .join(Iterables.transform(rolesAdded, ScreensaverUserRole.ToDisplayableRoleName)));
        }
        Set<ScreensaverUserRole> rolesRemoved = Sets.difference(_lastPrimaryRoles,
                getEntity().getPrimaryScreensaverUserRoles());
        if (!!!rolesRemoved.isEmpty()) {
            recordUpdateActivity("primary roles removed: " + Joiner.on(", ")
                    .join(Iterables.transform(rolesRemoved, ScreensaverUserRole.ToDisplayableRoleName)));
        }
        if (!StringUtils.isEmpty(_newPassword1)) {
            recordUpdateActivity("password updated");
        }
        super.recordUpdateActivity();
    }

    public List<SelectItem> getUserClassificationSelections() {
        List<ScreeningRoomUserClassification> userClassifications;
        // handle the special Principal Investigator classification, since this
        // value must be selected at creation time only, as it affects lab
        // affiliation and lab members editable
        if (((ScreeningRoomUser) getEntity()).isHeadOfLab()) {
            userClassifications = Arrays.asList(ScreeningRoomUserClassification.PRINCIPAL_INVESTIGATOR);
        } else {
            userClassifications = new ArrayList<ScreeningRoomUserClassification>(
                    Arrays.asList(ScreeningRoomUserClassification.values()));
            userClassifications.remove(ScreeningRoomUserClassification.PRINCIPAL_INVESTIGATOR);
        }
        if (getEntity().getEntityId() == null) {
            return JSFUtils.createUISelectItemsWithEmptySelection(userClassifications,
                    ScreensaverConstants.REQUIRED_VOCAB_FIELD_PROMPT);
        } else {
            return JSFUtils.createUISelectItems(userClassifications);
        }
    }

    public UISelectOneEntityBean<LabHead> getLabName() {
        assert isScreeningRoomUserViewMode() && !isLabHeadViewMode();
        if (_labName == null) {
            SortedSet<LabHead> labHeads = _usersDao.findAllLabHeads();
            _labName = new UISelectOneEntityBean<LabHead>(labHeads, getScreeningRoomUser().getLab().getLabHead(),
                    true, getDao()) {
                @Override
                protected String makeLabel(LabHead t) {
                    return t.getLab().getLabName();
                }

                @Override
                protected String getEmptyLabel() {
                    return getEntity().getEntityId() == null ? ScreensaverConstants.REQUIRED_VOCAB_FIELD_PROMPT
                            : super.getEmptyLabel();
                }
            };
        }
        return _labName;
    }

    public UISelectOneBean<Gender> getGender() {
        if (_gender == null) {
            Gender[] atList = Gender.values();
            _gender = new UISelectOneBean<Gender>(Lists.newArrayList(atList), getEntity().getGender(), true);
            //      {
            //        @Override
            //        protected String getEmptyLabel()
            //        {
            //          return UNKNOWN_SPECIES;
            //        }
            //      };
            _gender.addObserver(new Observer() {
                public void update(Observable arg0, Object at) {
                    getEntity().setGender((Gender) at);
                }
            });
        }
        return _gender;
    }

    public UISelectOneEntityBean<LabAffiliation> getLabAffiliation() {
        assert isLabHeadViewMode();
        if (_labAffiliation == null) {
            SortedSet<LabAffiliation> labAffiliations = new TreeSet<LabAffiliation>(
                    new NullSafeComparator<LabAffiliation>() {
                        @Override
                        protected int doCompare(LabAffiliation o1, LabAffiliation o2) {
                            return o1.getAffiliationName().compareTo(o2.getAffiliationName());
                        }
                    });
            labAffiliations.addAll(getDao().findAllEntitiesOfType(LabAffiliation.class));
            _labAffiliation = new UISelectOneEntityBean<LabAffiliation>(labAffiliations,
                    getScreeningRoomUser().getLab().getLabAffiliation(), true, getDao()) {
                @Override
                protected String makeLabel(LabAffiliation t) {
                    return t.getAffiliationName() + " (" + t.getAffiliationCategory() + ")";
                }
            };
        }
        return _labAffiliation;
    }

    public LabAffiliation getNewLabAffiliation() {
        if (_newLabAffiliation == null) {
            _newLabAffiliation = new LabAffiliation();
            _newLabAffiliation.setAffiliationCategory(DEFAULT_NEW_LAB_AFFILIATION_CATEGORY);
        }
        return _newLabAffiliation;
    }

    public List<SelectItem> getAffiliationCategorySelections() {
        return JSFUtils.createUISelectItems(Arrays.asList(AffiliationCategory.values()));
    }

    public DataModel getFacilityUsageRolesDataModel() {
        if (_facilityUsageRolesDataModel == null) {
            SortedSet<FacilityUsageRole> facilityUsages = Sets
                    .newTreeSet(getScreeningRoomUser().getFacilityUsageRoles());
            _facilityUsageRolesDataModel = new ListDataModel(Lists.newArrayList(facilityUsages));
        }
        return _facilityUsageRolesDataModel;
    }

    public UISelectOneBean<FacilityUsageRole> getNewFacilityUsageRole() {
        if (_newFacilityUsageRole == null) {
            Collection<FacilityUsageRole> candidateNewFacilityUsageRoles = Sets.difference(
                    Sets.newHashSet(FacilityUsageRole.values()), getScreeningRoomUser().getFacilityUsageRoles());
            _newFacilityUsageRole = new UISelectOneBean<FacilityUsageRole>(candidateNewFacilityUsageRoles, null,
                    true) {
                @Override
                protected String makeLabel(FacilityUsageRole fu) {
                    return fu.getDisplayableName();
                }

                @Override
                protected String getEmptyLabel() {
                    return ScreensaverConstants.REQUIRED_VOCAB_FIELD_PROMPT;
                }
            };
        }
        return _newFacilityUsageRole;
    }

    public DataModel getUserRolesDataModel() {
        if (_userRolesDataModel == null) {
            List<ScreensaverUserRole> userRoles = Lists.newArrayList(getEntity().getPrimaryScreensaverUserRoles());
            Collections.sort(userRoles, USER_ROLE_COMPARATOR);
            _userRolesDataModel = new ListDataModel(userRoles);
        }
        return _userRolesDataModel;
    }

    public UISelectOneBean<ScreensaverUserRole> getNewUserRole() {
        if (_newUserRole == null) {
            Collection<ScreensaverUserRole> candidateNewUserRoles = new TreeSet<ScreensaverUserRole>();
            for (ScreensaverUserRole userRole : ScreensaverUserRole.values()) {
                if (!userRole.isAdministrative() &&
                // hide if a user already has this role (primary or implied)
                        !getEntity().getScreensaverUserRoles().contains(userRole) &&
                        // hide if this role implies an extant primary user role (forces admin to remove the lower role first, before adding the higher role)
                        Sets.intersection(userRole.getImpliedRoles(), getEntity().getPrimaryScreensaverUserRoles())
                                .isEmpty()) {
                    candidateNewUserRoles.add(userRole);
                }
            }

            // At ICCB-L, the RNAi DSL 2 role is not an option, so we hide it at the UI level; we maintain it in our model for consistency with the SM DSL roles
            // TODO: refactor to share this logic with similar code in UserAgreementUpdater.getNewDataSharingLevel()
            if (getApplicationProperties().isFacility(IccblScreensaverConstants.FACILITY_KEY)) {
                candidateNewUserRoles.remove(ScreensaverUserRole.RNAI_DSL_LEVEL2_MUTUAL_POSITIVES);
            }

            _newUserRole = new UISelectOneBean<ScreensaverUserRole>(candidateNewUserRoles, null, true) {
                @Override
                protected String makeLabel(ScreensaverUserRole r) {
                    return r.getDisplayableRoleName();
                }

                @Override
                protected String getEmptyLabel() {
                    return ScreensaverConstants.REQUIRED_VOCAB_FIELD_PROMPT;
                }
            };
        }
        return _newUserRole;
    }

    public DataModel getRnaiScreensDataModel() {
        initScreensDataModels();
        return _screensDataModel.get(ScreenType.RNAI);
    }

    public DataModel getSmallMoleculeScreensDataModel() {
        initScreensDataModels();
        return _screensDataModel.get(ScreenType.SMALL_MOLECULE);
    }

    private void initScreensDataModels() {
        if (_screensDataModel == null && isScreeningRoomUserViewMode()) {
            List<ScreenAndRole> screensAndRoles = new ArrayList<ScreenAndRole>();
            for (Screen screen : getScreeningRoomUser().getAllAssociatedScreens()) {
                // note: if both Lead Screener and PI, show Lead Screener
                String role = getScreeningRoomUser().getScreensLed().contains(screen) ? "Lead Screener"
                        : (getLabHead() != null && getLabHead().getScreensHeaded().contains(screen))
                                ? "Lab Head (PI)"
                                : "Collaborator";
                if (!screen.isRestricted()) {
                    screensAndRoles.add(new ScreenAndRole(screen, role));
                }
            }
            Multimap<ScreenType, ScreenAndRole> screenType2ScreenAndRole = HashMultimap.create();
            for (ScreenAndRole screenAndRole : screensAndRoles) {
                screenType2ScreenAndRole.put(screenAndRole.getScreen().getScreenType(), screenAndRole);
            }
            _screensDataModel = new HashMap<ScreenType, DataModel>();
            for (ScreenType screenType : ScreenType.values()) {
                if (screenType2ScreenAndRole.containsKey(screenType)) {
                    ArrayList<ScreenAndRole> screensAndRolesOfType = new ArrayList<ScreenAndRole>(
                            screenType2ScreenAndRole.get(screenType));
                    Collections.sort(screensAndRolesOfType);
                    _screensDataModel.put(screenType, new ListDataModel(screensAndRolesOfType));
                }
            }
        }
    }

    public DataModel getLabMembersDataModel() {
        if (_labMembersDataModel == null && isScreeningRoomUserViewMode()) {
            _labMembersDataModel = new ListDataModel(Ordering.from(ScreensaverUserComparator.getInstance())
                    .sortedCopy(getScreeningRoomUser().getLab().getLabMembers()));
        }
        return _labMembersDataModel;
    }

    public DataModel getScreenAssociatesDataModel() {
        if (_screenAssociatesDataModel == null && isScreeningRoomUserViewMode()) {
            Set<ScreeningRoomUser> screenAssociates = new TreeSet<ScreeningRoomUser>(
                    ScreensaverUserComparator.getInstance());
            // note: we only want associates from the user's screens, and not *all* of
            // his associates, as returned by user.getAssociatedUsers(), since this
            // also returns lab members and lab head (which are shown elsewhere by
            // this viewer)
            for (Screen screen : getScreeningRoomUser().getAllAssociatedScreens()) {
                screenAssociates.addAll(screen.getAssociatedScreeningRoomUsers());
            }
            screenAssociates.remove(getScreeningRoomUser());
            _screenAssociatesDataModel = new ListDataModel(Lists.newArrayList(screenAssociates));
        }
        return _screenAssociatesDataModel;
    }

    public AttachedFiles getAttachedFiles() {
        return _attachedFiles;
    }

    public ChecklistItems getChecklistItems() {
        return _checklistItems;
    }

    public String getNewPassword1() {
        return _newPassword1;
    }

    public void setNewPassword1(String newPassword1) {
        _newPassword1 = newPassword1;
    }

    public String getNewPassword2() {
        return _newPassword2;
    }

    public void setNewPassword2(String newPassword2) {
        _newPassword2 = newPassword2;
    }

    @Override
    protected void initializeNewEntity(ScreeningRoomUser newUser) {
        ScreensaverUser currentUser = getScreensaverUser();
        if (newUser instanceof LabHead && !(currentUser instanceof AdministratorUser
                && ((AdministratorUser) currentUser).isUserInRole(ScreensaverUserRole.LAB_HEADS_ADMIN))) {
            throw new OperationRestrictedException("add a new lab head");
        }
    }

    private void warnAdminOnMismatchedLabMemberDataSharingLevel(ScreeningRoomUser user, ScreenType screenType) {
        if (isReadAdmin()) {
            if (!!!user.isHeadOfLab()) {
                if (user.getLab().getLabHead() != null) {
                    ScreensaverUserRole labHeadLeastRestrictiveRole = DataSharingLevelMapper
                            .getPrimaryDataSharingLevelRoleForUser(screenType, user.getLab().getLabHead());
                    if (labHeadLeastRestrictiveRole != null) {
                        ScreensaverUserRole userLeastRestrictiveRole = DataSharingLevelMapper
                                .getPrimaryDataSharingLevelRoleForUser(screenType, user);
                        if (userLeastRestrictiveRole != null) {
                            if (labHeadLeastRestrictiveRole.compareTo(userLeastRestrictiveRole) > 0) {
                                showMessage("users.dataSharingLevelTooRestrictive",
                                        userLeastRestrictiveRole.getDisplayableRoleName(),
                                        labHeadLeastRestrictiveRole.getDisplayableRoleName());
                            } else if (labHeadLeastRestrictiveRole.compareTo(userLeastRestrictiveRole) < 0) {
                                showMessage("users.dataSharingLevelTooLoose",
                                        userLeastRestrictiveRole.getDisplayableRoleName(),
                                        labHeadLeastRestrictiveRole.getDisplayableRoleName());
                            }
                        }
                    }
                }
            }
        }
    }

    private void warnAdminOnLabHeadScreensTooRestrictive(ScreeningRoomUser user) {
        if (isReadAdmin()) {
            if (user.isHeadOfLab()) {
                LabHead labHead = (LabHead) user;
                for (Screen screen : labHead.getScreensHeaded()) {
                    if (screen.getDataSharingLevel().compareTo(DataSharingLevelMapper
                            .getScreenDataSharingLevelForUser(screen.getScreenType(), labHead)) > 0) {
                        showMessage("users.labHeadScreenTooRestrictive", screen.getFacilityId(),
                                screen.getDataSharingLevel());
                    }
                }
            }
        }
    }

    @UICommand
    public String addFacilityUsageRole() {
        if (getNewFacilityUsageRole().getSelection() != null) {
            getScreeningRoomUser().getFacilityUsageRoles().add(getNewFacilityUsageRole().getSelection());
            _newFacilityUsageRole = null;
            _facilityUsageRolesDataModel = null;
        }
        return REDISPLAY_PAGE_ACTION_RESULT;
    }

    @UICommand
    public String deleteFacilityUsageRole() {
        FacilityUsageRole facilityUsage = (FacilityUsageRole) getRequestMap().get("element");
        getScreeningRoomUser().getFacilityUsageRoles().remove(facilityUsage);
        _newFacilityUsageRole = null;
        _facilityUsageRolesDataModel = null;
        return REDISPLAY_PAGE_ACTION_RESULT;
    }

    @UICommand
    public String addUserRole() {
        if (getNewUserRole().getSelection() != null) {
            getEntity().addScreensaverUserRole(getNewUserRole().getSelection());
            _newUserRole = null;
            _userRolesDataModel = null;
        }
        return REDISPLAY_PAGE_ACTION_RESULT;
    }

    @UICommand
    public String deleteUserRole() {
        ScreensaverUserRole primaryRole = (ScreensaverUserRole) getRequestMap().get("element");
        getEntity().removeScreensaverUserRole(primaryRole);
        _newUserRole = null;
        _userRolesDataModel = null;
        return REDISPLAY_PAGE_ACTION_RESULT;
    }

    @UICommand
    @Transactional
    public String addNewLabAffiliation() {
        if (StringUtils.isEmpty(_newLabAffiliation.getAffiliationName())) {
            reportApplicationError("new lab affiliation name is required");
            return REDISPLAY_PAGE_ACTION_RESULT;
        }
        if (getDao().findEntityByProperty(LabAffiliation.class, "affiliationName",
                _newLabAffiliation.getAffiliationName()) != null) {
            showMessage("duplicateEntity", "lab affiliation");
            return REDISPLAY_PAGE_ACTION_RESULT;
        }
        getDao().persistEntity(_newLabAffiliation);
        getDao().flush();

        // force reload of lab affiliation selections
        _labAffiliation = null;

        // set user's lab affiliation to new affiliation
        getLabAffiliation().setSelection(_newLabAffiliation);

        _newLabAffiliation = null;
        return REDISPLAY_PAGE_ACTION_RESULT;
    }

    @UICommand
    @Transactional(readOnly = true)
    public String addLabMember() {
        if (!isLabHeadViewMode()) {
            reportApplicationError("can only create lab members for lab heads");
            return REDISPLAY_PAGE_ACTION_RESULT;
        }
        if (isEditMode()) {
            reportApplicationError("cannot add lab members while editing lab head");
            return REDISPLAY_PAGE_ACTION_RESULT;
        }
        ScreeningRoomUser labHead = getDao().reloadEntity(getEntity());
        ScreeningRoomUser newLabMember = new ScreeningRoomUser((AdministratorUser) getScreensaverUser());
        newLabMember.setLab(labHead.getLab());
        return getThisProxy().editNewEntity(newLabMember);
    }

    @UICommand
    @Transactional(readOnly = true)
    public String addScreen() {
        return doAddScreen(null);
    }

    @UICommand
    @Transactional(readOnly = true)
    public String addRnaiScreen() {
        return doAddScreen(ScreenType.RNAI);
    }

    @UICommand
    @Transactional(readOnly = true)
    public String addSmallMoleculeScreen() {
        return doAddScreen(ScreenType.SMALL_MOLECULE);
    }

    private String doAddScreen(ScreenType screenType) {
        if (!isScreeningRoomUserViewMode()) {
            throw new DevelopmentException("cannot create screen for administrator user");
        }
        if (isEditMode()) {
            throw new DevelopmentException("cannot create screen while editing user");
        }
        Screen screen = _screenGenerator.createPrimaryScreen((AdministratorUser) getScreensaverUser(), getEntity(),
                screenType);
        return _screenDetailViewer.editNewEntity(screen);
    }

    @UICommand
    public String addServiceActivity() {
        AdministratorUser admin = (AdministratorUser) getScreensaverUser();
        if (!admin.getScreensaverUserRoles().contains(ScreensaverUserRole.SERVICE_ACTIVITY_ADMIN)) {
            throw new OperationRestrictedException(
                    "admin user does not have the " + ScreensaverUserRole.SERVICE_ACTIVITY_ADMIN + " role");
        }
        return _activityViewer.editNewEntity(new ServiceActivity(admin, admin, new LocalDate(), null, getEntity()));
    }

    @UICommand
    public String browseScreens() {
        return doBrowseScreens(null);
    }

    @UICommand
    public String browseRnaiScreens() {
        return doBrowseScreens(ScreenType.RNAI);
    }

    @UICommand
    public String browseSmallMoleculeScreens() {
        return doBrowseScreens(ScreenType.SMALL_MOLECULE);
    }

    private String doBrowseScreens(ScreenType screenType) {
        _screensBrowser.searchScreensForUser(getScreeningRoomUser());
        if (screenType != null) {
            _screensBrowser.getColumnManager().getColumn("Screen Type").clearCriteria()
                    .addCriterion(new Criterion(Operator.EQUAL, screenType));
        }
        return BROWSE_SCREENS;
    }

    @SuppressWarnings("unchecked")
    @UICommand
    public String browseLabMembers() {
        HashSet<ScreeningRoomUser> labMembers = Sets
                .newHashSet((List<ScreeningRoomUser>) getLabMembersDataModel().getWrappedData());
        ((UserSearchResults) getContextualSearchResults()).searchUsers(labMembers,
                "Lab Members of lab " + getEntity().getLab().getLabName());
        return BROWSE_SCREENERS;
    }

    @SuppressWarnings("unchecked")
    @UICommand
    public String browseScreenAssociates() {
        HashSet<ScreeningRoomUser> associates = Sets
                .newHashSet((List<ScreeningRoomUser>) getScreenAssociatesDataModel().getWrappedData());
        ((UserSearchResults) getContextualSearchResults()).searchUsers(associates,
                "Screening Associates of screener " + getEntity().getFullNameFirstLast());
        return BROWSE_SCREENERS;
    }

    @Override
    protected String postEditAction(EditResult editResult) {
        switch (editResult) {
        case CANCEL_EDIT:
            return getThisProxy().reload();
        case SAVE_EDIT:
            return getThisProxy().reload();
        case CANCEL_NEW:
            return VIEW_MAIN;
        case SAVE_NEW:
            return getThisProxy().reload();
        default:
            return null;
        }
    }

    public int getUserActivitiesCount() {
        return getEntity().getAssociatedActivities().size();
    }

    public Activity getLastUserActivity() {
        if (getEntity().getAssociatedActivities().isEmpty()) {
            return null;
        }
        return getEntity().getAssociatedActivities().last();
    }

    @UICommand
    public String browseUserActivities() {
        _activitiesBrowser.searchActivitiesForUser(getEntity());
        return BROWSE_ACTIVITIES;
    }
}