edu.harvard.med.iccbl.screensaver.policy.IccblEntityViewPolicy.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.med.iccbl.screensaver.policy.IccblEntityViewPolicy.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.iccbl.screensaver.policy;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Predicates;

import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.log4j.Logger;
import org.hibernate.Session;

import edu.harvard.med.screensaver.db.Criterion.Operator;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.Query;
import edu.harvard.med.screensaver.db.hqlbuilder.HqlBuilder;
import edu.harvard.med.screensaver.db.hqlbuilder.JoinType;
import edu.harvard.med.screensaver.model.activities.AdministrativeActivity;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickLiquidTransfer;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickRequest;
import edu.harvard.med.screensaver.model.cherrypicks.RNAiCherryPickRequest;
import edu.harvard.med.screensaver.model.cherrypicks.SmallMoleculeCherryPickRequest;
import edu.harvard.med.screensaver.model.libraries.Library;
import edu.harvard.med.screensaver.model.libraries.SilencingReagent;
import edu.harvard.med.screensaver.model.libraries.SmallMoleculeReagent;
import edu.harvard.med.screensaver.model.screenresults.AnnotationType;
import edu.harvard.med.screensaver.model.screenresults.AnnotationValue;
import edu.harvard.med.screensaver.model.screenresults.AssayWell;
import edu.harvard.med.screensaver.model.screenresults.DataColumn;
import edu.harvard.med.screensaver.model.screenresults.ResultValue;
import edu.harvard.med.screensaver.model.screenresults.ScreenResult;
import edu.harvard.med.screensaver.model.screens.CherryPickScreening;
import edu.harvard.med.screensaver.model.screens.LabActivity;
import edu.harvard.med.screensaver.model.screens.LibraryScreening;
import edu.harvard.med.screensaver.model.screens.Screen;
import edu.harvard.med.screensaver.model.screens.ScreenDataSharingLevel;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.screens.Study;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.LabHead;
import edu.harvard.med.screensaver.model.users.ScreeningRoomUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUserRole;
import edu.harvard.med.screensaver.policy.CurrentScreensaverUser;
import edu.harvard.med.screensaver.policy.DefaultEntityViewPolicy;

/**
 * An EntityViewPolicy implementation for ICCB-Longwood that is used by the production web application. 
 */
public class IccblEntityViewPolicy extends DefaultEntityViewPolicy {
    public static final String GRAY_LIBRARY_SCREEN_FUNDING_SUPPORT_NAME = "Gray Library Screen";

    private static Logger log = Logger.getLogger(IccblEntityViewPolicy.class);

    private CurrentScreensaverUser _currentScreensaverUser;
    private ScreensaverUser _screensaverUser;
    private GenericEntityDAO _dao;
    private Set<Screen> _myScreens;
    private Set<Screen> _publicScreens;
    private HashMultimap<String, Screen> _screensForFundingSupport = HashMultimap.create();
    private Set<Screen> _othersVisibleScreens;
    private Map<ScreenType, Set<Screen>> _level1AndLevel2Screens;
    private Set<Screen> _mutualScreens;
    private Set<Screen> _mutualPositiveScreens;
    private Set<String> _mutualPositiveWellIds;
    private Set<Integer> _mutualPositiveScreenResultIds;

    protected IccblEntityViewPolicy() {
    }

    public IccblEntityViewPolicy(CurrentScreensaverUser user, GenericEntityDAO dao) {
        _currentScreensaverUser = user;
        _dao = dao;
    }

    /**
     * @motivation for unit tests
     */
    public IccblEntityViewPolicy(ScreensaverUser user, GenericEntityDAO dao) {
        _screensaverUser = user;
        _dao = dao;
    }

    public ScreensaverUser getScreensaverUser() {
        if (_screensaverUser == null) {
            _screensaverUser = _currentScreensaverUser.getScreensaverUser();
        }
        return _screensaverUser;
    }

    public AdministrativeActivity visit(AdministrativeActivity entity) {
        return getScreensaverUser().getScreensaverUserRoles().contains(ScreensaverUserRole.READ_EVERYTHING_ADMIN)
                ? entity
                : null;
    }

    public AnnotationType visit(AnnotationType entity) {
        return visit((Study) entity.getStudy()) == null ? null : entity;
    }

    public AnnotationValue visit(AnnotationValue entity) {
        return visit(entity.getAnnotationType()) == null ? null : entity;
    }

    public CherryPickLiquidTransfer visit(CherryPickLiquidTransfer entity) {
        return visit((LabActivity) entity) == null ? null : entity;
    }

    public Library visit(Library entity) {
        ScreeningRoomUser owner = entity.getOwner();
        ScreensaverUser user = getScreensaverUser();

        // Equals is based on EntityId if present, otherwise by instance equality
        //In this example case Entity id is empty, so comparison is based on instance
        //I assume that normally this field is not empty

        //if owner == null : not a validation library 
        //TODO add || isLabheadLibraryOwner(owner) , however this gives currently "No session" error.
        return owner == null || owner.equals(user)
                || user.getScreensaverUserRoles().contains(ScreensaverUserRole.LIBRARIES_ADMIN) ? entity : null;
    }

    public ResultValue visit(ResultValue entity) {
        // exceptions for positive RVs, allowing a subset of RVs to be visible, even if screen result is not visible
        if (isAllowedAccessToResultValueDueToMutualPositive(entity.isPositive(),
                entity.getDataColumn().getScreenResult().getScreen(), entity.getWell().getWellId())) {
            return entity;
        }

        return visit(entity.getDataColumn().getScreenResult()) == null ? null : entity;
    }

    @Override
    public boolean isAllowedAccessToResultValueDueToMutualPositive(boolean isPositive, Screen screen,
            String wellId) {
        if (isPositive) {
            if (findOthersVisibleScreens().contains(screen)) {
                if (findMutualPositiveWellIds().contains(wellId)) {
                    return true;
                }
            }
        }
        return false;
    }

    public DataColumn visit(DataColumn entity) {
        if (visit(entity.getScreenResult()) != null) {
            return entity;
        } else if (isAllowedAccessToDataColumnDueToMutualPositives(entity)) {
            return entity;
        }
        return null;
    }

    @Override
    public boolean isAllowedAccessToDataColumnDueToMutualPositives(DataColumn entity) {
        // allow DataColumn containing mutual positives to be visible, even if the parent screen result is not visible
        // note: currently, we show all positives DataColumns from a given screen to be visible if any *one* of its positives DataColumns 
        // have a mutual positive; we could make this even more strict by restricting the positives DataColumns that have no mutual positives
        if (entity.isPositiveIndicator()) {
            if (visit(entity.getScreenResult()) == null) {
                if (findOthersVisibleScreens().contains(entity.getScreenResult().getScreen())) {
                    return findMutualPositiveScreenResultIds().contains(entity.getScreenResult().getEntityId());
                }
            }
        }
        return false;
    }

    public Study visit(Study entity) {
        return visit((Screen) entity);
    }

    public Screen visit(Screen screen) {
        ScreensaverUser user = getScreensaverUser();
        if (user.getScreensaverUserRoles().contains(ScreensaverUserRole.GRAY_ADMIN)) {
            return findScreensForFundingSupport(GRAY_LIBRARY_SCREEN_FUNDING_SUPPORT_NAME).contains(screen) ? screen
                    : null;
        }
        if (user.getScreensaverUserRoles().contains(ScreensaverUserRole.READ_EVERYTHING_ADMIN)
                || user.getScreensaverUserRoles().contains(ScreensaverUserRole.SCREENS_ADMIN)) {
            return screen;
        }
        if (findMyScreens().contains(screen)) {
            log.debug("screen " + screen.getFacilityId() + " is visible: \"my screen\"");
            return screen;
        }
        if (findPublicScreens().contains(screen)) {
            log.debug("screen " + screen.getFacilityId() + " is visible: \"public\"");
            return screen;
        }
        if (findOthersVisibleScreens().contains(screen)) {
            log.debug("screen " + screen.getFacilityId() + " is visible: \"screen shared by others\"");
            return screen;
        }
        return null;
    }

    private Set<Screen> findOthersVisibleScreens() {
        if (_othersVisibleScreens == null) {
            _othersVisibleScreens = Sets.newHashSet();
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.SM_DSL_LEVEL2_MUTUAL_POSITIVES)) { // note: this implies level 1 users too! 
                if (userHasQualifiedDepositedData(ScreenType.SMALL_MOLECULE)) {
                    _othersVisibleScreens.addAll(findOthersLevel1AndLevel2Screens(ScreenType.SMALL_MOLECULE));
                }
            }
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.RNAI_DSL_LEVEL2_MUTUAL_POSITIVES)) { // note: this implies level 1 users too! 
                if (userHasQualifiedDepositedData(ScreenType.RNAI)) {
                    _othersVisibleScreens.addAll(findOthersLevel1AndLevel2Screens(ScreenType.RNAI));
                }
            }
        }
        return _othersVisibleScreens;
    }

    private boolean userHasQualifiedDepositedData(ScreenType screenType) {
        // level 1 users must have at least one level 0 or 1 screen to qualify (i.e., a level 1 user does NOT qualify with only a level 2 screen)
        // level 2 users must have at least one level 0, 1, or 2 screen to qualify
        ScreenDataSharingLevel maxQualifyingScreenDataSharingLevel = ScreenDataSharingLevel.MUTUAL_POSITIVES;
        if (getScreensaverUser().getScreensaverUserRoles()
                .contains(DataSharingLevelMapper.getUserDslRoleForScreenTypeAndLevel(screenType, 1))) {
            maxQualifyingScreenDataSharingLevel = ScreenDataSharingLevel.MUTUAL_SCREENS;
        }
        for (Screen myScreen : findMyScreens()) {
            if (myScreen.getScreenType() == screenType) {
                if (myScreen.getDataSharingLevel().compareTo(maxQualifyingScreenDataSharingLevel) <= 0) {
                    if (myScreen.getScreenResult() != null) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private Set<String> findMutualPositiveWellIds() {
        if (_mutualPositiveWellIds == null) {
            _mutualPositiveWellIds = Sets.newHashSet();
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.SM_DSL_LEVEL2_MUTUAL_POSITIVES)) {
                _mutualPositiveWellIds.addAll(findMutualPositiveWellIds(ScreenType.SMALL_MOLECULE));
            }
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.RNAI_DSL_LEVEL2_MUTUAL_POSITIVES)) {
                _mutualPositiveWellIds.addAll(findMutualPositiveWellIds(ScreenType.RNAI));
            }
        }
        return _mutualPositiveWellIds;
    }

    @SuppressWarnings("unchecked")
    private Set<String> findMutualPositiveWellIds(final ScreenType screenType) {
        return Sets.newHashSet(_dao.<String>runQuery(new Query() {
            public List execute(Session session) {
                return new HqlBuilder().select("lw2", "id").distinctProjectionValues().from(AssayWell.class, "aw1")
                        .from("aw1", AssayWell.screenResult, "sr1", JoinType.INNER)
                        .from("sr1", ScreenResult.screen, "s1", JoinType.INNER).from(AssayWell.class, "aw2")
                        .from("aw2", AssayWell.screenResult, "sr2", JoinType.INNER)
                        .from("sr2", ScreenResult.screen, "s2", JoinType.INNER)
                        .from("aw2", AssayWell.libraryWell, "lw2", JoinType.INNER)
                        .where("aw1", "libraryWell", Operator.EQUAL, "aw2", "libraryWell")
                        .where("aw1", "positive", Operator.EQUAL, Boolean.TRUE)
                        .where("aw2", "positive", Operator.EQUAL, Boolean.TRUE)
                        .where("s1", "screenType", Operator.EQUAL, screenType)
                        .where("s2", "screenType", Operator.EQUAL, screenType).where("s1", Operator.NOT_EQUAL, "s2")
                        . // don't consider my screens as "others" screens
                whereIn("s1", findMyScreens())
                        .whereIn("s1", "dataSharingLevel", Sets.newHashSet(ScreenDataSharingLevel.SHARED,
                                ScreenDataSharingLevel.MUTUAL_POSITIVES, ScreenDataSharingLevel.MUTUAL_SCREENS))
                        .whereIn("s2", "dataSharingLevel", Sets.newHashSet(ScreenDataSharingLevel.MUTUAL_POSITIVES,
                                ScreenDataSharingLevel.MUTUAL_SCREENS))
                        .toQuery(session, true).list();
            }
        }));
    }

    private Set<Screen> findMutualPositiveScreens() {
        // NOTE: #148 - Level 2 screeners can see details for mutual positive screens
        if (_mutualPositiveScreens == null) {
            Set<Screen> screens = Sets.newHashSet();
            Set<Integer> mprs = findMutualPositiveScreenResultIds();
            Set<Screen> others = findOthersVisibleScreens();
            for (Screen s : others) {
                if (s.getScreenResult() != null && mprs.contains(s.getScreenResult().getScreenResultId())) {
                    screens.add(s);
                }
            }
            _mutualPositiveScreens = screens;
        }
        return _mutualPositiveScreens;
    }

    private Set<Integer> findMutualPositiveScreenResultIds() {
        if (_mutualPositiveScreenResultIds == null) {
            _mutualPositiveScreenResultIds = Sets.newHashSet();
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.SM_DSL_LEVEL2_MUTUAL_POSITIVES)) {
                _mutualPositiveScreenResultIds.addAll(findMutualPositiveScreenResultIds(ScreenType.SMALL_MOLECULE));
            }
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.RNAI_DSL_LEVEL2_MUTUAL_POSITIVES)) {
                _mutualPositiveScreenResultIds.addAll(findMutualPositiveScreenResultIds(ScreenType.RNAI));
            }
        }
        return _mutualPositiveScreenResultIds;
    }

    @SuppressWarnings("unchecked")
    private Set<Integer> findMutualPositiveScreenResultIds(final ScreenType screenType) {
        return Sets.newHashSet(_dao.<Integer>runQuery(new Query() {
            public List execute(Session session) {
                // TODO: can probably optimize by using ANY operator to determine if at least one mutual positive hit occurs in another screen
                return new HqlBuilder().select("sr2", "id").distinctProjectionValues().from(AssayWell.class, "aw1")
                        .from("aw1", AssayWell.screenResult, "sr1", JoinType.INNER)
                        .from("sr1", ScreenResult.screen, "s1", JoinType.INNER).from(AssayWell.class, "aw2")
                        .from("aw2", AssayWell.screenResult, "sr2", JoinType.INNER)
                        .from("sr2", ScreenResult.screen, "s2", JoinType.INNER)
                        .where("aw1", "libraryWell", Operator.EQUAL, "aw2", "libraryWell")
                        .where("aw1", "positive", Operator.EQUAL, Boolean.TRUE)
                        .where("aw2", "positive", Operator.EQUAL, Boolean.TRUE)
                        .where("s1", "screenType", Operator.EQUAL, screenType)
                        .where("s2", "screenType", Operator.EQUAL, screenType).where("s1", Operator.NOT_EQUAL, "s2")
                        . // don't consider my screens as "others" screens
                whereIn("s1", findMyScreens())
                        .whereIn("s1", "dataSharingLevel", Sets.newHashSet(ScreenDataSharingLevel.SHARED,
                                ScreenDataSharingLevel.MUTUAL_POSITIVES, ScreenDataSharingLevel.MUTUAL_SCREENS))
                        .whereIn("s2", "dataSharingLevel", Sets.newHashSet(ScreenDataSharingLevel.MUTUAL_POSITIVES,
                                ScreenDataSharingLevel.MUTUAL_SCREENS))
                        .toQuery(session, true).list();
            }
        }));
    }

    private Set<Screen> findOthersLevel1AndLevel2Screens(final ScreenType screenType) {
        if (_level1AndLevel2Screens == null) {
            _level1AndLevel2Screens = Maps.newHashMap();
        }
        if (!_level1AndLevel2Screens.containsKey(screenType)) {
            HashSet<Screen> screens = Sets.<Screen>newHashSet();
            _level1AndLevel2Screens.put(screenType, screens);
            screens.addAll(_dao.<Screen>runQuery(new Query() {
                public List execute(Session session) {
                    org.hibernate.Query query = session.createQuery(
                            "select distinct s from Screen s where s.screenType = :screenType and s.dataSharingLevel in (:dataSharingLevels) and s not in (:myScreens)");
                    query.setParameter("screenType", screenType);
                    query.setParameterList("dataSharingLevels", Sets.newHashSet(
                            ScreenDataSharingLevel.MUTUAL_POSITIVES, ScreenDataSharingLevel.MUTUAL_SCREENS));
                    query.setParameterList("myScreens", findMyScreens());
                    return query.list();
                }
            }));
            if (log.isDebugEnabled()) {
                log.debug("others' level 1 and level 2 " + screenType + " screens : " + Joiner.on(", ")
                        .join(Iterables.transform(_level1AndLevel2Screens.get(screenType), Screen.ToNameFunction)));
            }
        }
        return _level1AndLevel2Screens.get(screenType);
    }

    private Set<Screen> findMutualScreens() {
        if (_mutualScreens == null) {
            _mutualScreens = Sets.newHashSet();
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.SM_DSL_LEVEL1_MUTUAL_SCREENS)) {
                _mutualScreens.addAll(findOthersLevel1AndLevel2Screens(ScreenType.SMALL_MOLECULE));
            }
            if (getScreensaverUser().getScreensaverUserRoles()
                    .contains(ScreensaverUserRole.RNAI_DSL_LEVEL1_MUTUAL_SCREENS)) {
                _mutualScreens.addAll(findOthersLevel1AndLevel2Screens(ScreenType.RNAI));
            }
            // filter out the level 2 screens, since we've called findOthersLevel1AndLevel2Screens() for code reuse, even though it returns a superset of screens that we need in this method
            _mutualScreens = Sets.newHashSet(Iterables.filter(_mutualScreens, Predicates.compose(
                    Predicates.equalTo(ScreenDataSharingLevel.MUTUAL_SCREENS), Screen.ToDataSharingLevel)));
            if (log.isDebugEnabled()) {
                log.debug("other's mutually shared screens: "
                        + Joiner.on(", ").join(Iterables.transform(_mutualScreens, Screen.ToNameFunction)));
            }
        }
        return _mutualScreens;
    }

    private Set<Screen> findMyScreens() {
        if (_myScreens == null) {
            if (getScreensaverUser() instanceof ScreeningRoomUser) {
                _myScreens = ((ScreeningRoomUser) getScreensaverUser()).getAllAssociatedScreens();
            } else {
                _myScreens = Sets.newHashSet();
            }
        }
        return _myScreens;
    }

    private Set<Screen> findPublicScreens() {
        if (_publicScreens == null) {
            _publicScreens = Sets.newHashSet();
            _publicScreens.addAll(_dao.<Screen>runQuery(new Query() {
                public List execute(Session session) {
                    Set<ScreenType> screenTypes = Sets.newHashSet();
                    if (getScreensaverUser().isUserInRole(ScreensaverUserRole.RNAI_DSL_LEVEL3_SHARED_SCREENS)) {
                        screenTypes.add(ScreenType.RNAI);
                    }
                    if (getScreensaverUser().isUserInRole(ScreensaverUserRole.SM_DSL_LEVEL3_SHARED_SCREENS)) {
                        screenTypes.add(ScreenType.SMALL_MOLECULE);
                    }
                    return new HqlBuilder().from(Screen.class, "s")
                            .where("s", "dataSharingLevel", Operator.EQUAL, ScreenDataSharingLevel.SHARED)
                            .whereIn("s", "screenType", screenTypes).toQuery(session, true).list();
                }
            }));
        }
        return _publicScreens;
    }

    private Set<Screen> findScreensForFundingSupport(final String fundingSupportName) {
        if (!!!_screensForFundingSupport.containsKey(fundingSupportName)) {
            _screensForFundingSupport.putAll(fundingSupportName, _dao.<Screen>runQuery(new Query() {
                public List execute(Session session) {
                    return new HqlBuilder().select("s").from(Screen.class, "s")
                            .from("s", Screen.fundingSupports, "fs")
                            .where("fs", "value", Operator.EQUAL, fundingSupportName).toQuery(session, true).list();
                }
            }));
        }
        return _screensForFundingSupport.get(fundingSupportName);
    }

    public ScreenResult visit(ScreenResult entity) {
        return isAllowedAccessToScreenDetails(entity.getScreen()) ? entity : null;
    }

    public ScreeningRoomUser visit(ScreeningRoomUser entity) {
        ScreensaverUser loggedInUser = getScreensaverUser();
        if (loggedInUser.getScreensaverUserRoles().contains(ScreensaverUserRole.READ_EVERYTHING_ADMIN)) {
            return entity;
        }
        if (loggedInUser.equals(entity)) {
            return entity;
        }
        if (loggedInUser instanceof ScreeningRoomUser) {
            return ((ScreeningRoomUser) loggedInUser).getAssociatedUsers().contains(entity) ? entity : null;
        }
        return null;
    }

    public LabHead visit(LabHead entity) {
        return visit((ScreeningRoomUser) entity) == null ? null : entity;
    }

    public AdministratorUser visit(AdministratorUser entity) {
        ScreensaverUser loggedInUser = getScreensaverUser();
        if (loggedInUser.getScreensaverUserRoles().contains(ScreensaverUserRole.READ_EVERYTHING_ADMIN)) {
            return entity;
        }
        if (loggedInUser.equals(entity)) {
            return entity;
        }
        return null;
    }

    public SilencingReagent visit(SilencingReagent entity) {
        if (!!!getScreensaverUser().isUserInRole(ScreensaverUserRole.READ_EVERYTHING_ADMIN)
                && entity.isRestrictedSequence()) {
            SequenceRestrictedSilencingReagent sequenceRestrictedSilencingReagent = new SequenceRestrictedSilencingReagent(
                    entity);
            if (log.isDebugEnabled()) {
                log.debug("returning sequence-restricted silencing reagent: " + sequenceRestrictedSilencingReagent);
            }
            return sequenceRestrictedSilencingReagent;
        }
        return entity;
    }

    public SmallMoleculeReagent visit(SmallMoleculeReagent entity) {
        if (!!!getScreensaverUser().isUserInRole(ScreensaverUserRole.READ_EVERYTHING_ADMIN)
                && entity.isRestrictedStructure()) {
            StructureRestrictedSmallMoleculeReagent structureRestrictedSmallMoleculeReagent = new StructureRestrictedSmallMoleculeReagent(
                    entity);
            if (log.isDebugEnabled()) {
                log.debug("returning structure-restricted small molecule reagent: "
                        + structureRestrictedSmallMoleculeReagent);
            }
            return structureRestrictedSmallMoleculeReagent;
        }
        return entity;
    }

    public SmallMoleculeCherryPickRequest visit(SmallMoleculeCherryPickRequest entity) {
        return (SmallMoleculeCherryPickRequest) visit((CherryPickRequest) entity);
    }

    public RNAiCherryPickRequest visit(RNAiCherryPickRequest entity) {
        return (RNAiCherryPickRequest) visit((CherryPickRequest) entity);
    }

    public LibraryScreening visit(LibraryScreening entity) {
        return (LibraryScreening) visit((LabActivity) entity);
    }

    public CherryPickScreening visit(CherryPickScreening entity) {
        return (CherryPickScreening) visit((LabActivity) entity);
    }

    /**
     * @return true if user should be allowed to view the Screen's summary,
     *         publishable protocol, screening summary, and screen result data.
     */
    public boolean isAllowedAccessToScreenDetails(Screen screen)
    // NOTE: #148 - This method allows access to Screen properties and results, everything
    // , therefore, it is not appropriate for level2 screeners viewing mutual
    // positive screens
    {
        if (visit(screen) == null) {
            return false;
        }
        return isReadEverythingAdmin() || findMyScreens().contains(screen) || findPublicScreens().contains(screen)
                || findMutualScreens().contains(screen);
        // Note: if mutual positive screens were to be completely visible to level2 screeners, 
        // then add this clause.
        //      || findMutualPositiveScreens().contains(screen);
    }

    public boolean isAllowedAccessToMutualScreenDetails(Screen screen) {
        // NOTE: added for #148 - Level 2 screeners can see details for mutual positive screens
        if (visit(screen) == null) {
            return false;
        }
        return isReadEverythingAdmin() || findMyScreens().contains(screen) || findPublicScreens().contains(screen)
                || findMutualScreens().contains(screen) || findMutualPositiveScreens().contains(screen);
    }

    /**
     * Determine whether the current user can see the Status Items, Lab
     * Activities, and Cherry Pick Requests tables. These are considered more
     * private than the screen details (see
     * {@link IccblEntityViewPolicy#isAllowedAccessToScreenDetails(Screen)}).
     */
    public boolean isAllowedAccessToScreenActivity(Screen screen) {
        if (visit(screen) == null) {
            return false;
        }
        return isReadEverythingAdmin() || findMyScreens().contains(screen);
    }

    private CherryPickRequest visit(CherryPickRequest entity) {
        return isAllowedAccessToScreenActivity(entity.getScreen()) ? entity : null;
    }

    private LabActivity visit(LabActivity entity) {
        return isAllowedAccessToScreenActivity(entity.getScreen()) ? entity : null;
    }

    private boolean isReadEverythingAdmin() {
        return getScreensaverUser().getScreensaverUserRoles().contains(ScreensaverUserRole.READ_EVERYTHING_ADMIN);
    }

    /**
     * Causes access permissions for the user to be recomputed.  Should be called when the user's associations with entities have changed.  
     */
    public void update() {
        _screensForFundingSupport = HashMultimap.create();
        _level1AndLevel2Screens = null;
        _mutualPositiveWellIds = null;
        _mutualPositiveScreenResultIds = null;
        _mutualScreens = null;
        _myScreens = null;
        _othersVisibleScreens = null;
        _publicScreens = null;
    }

}