edu.harvard.med.iccbl.screensaver.service.screens.ScreenDataSharingLevelUpdater.java Source code

Java tutorial

Introduction

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

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;

import org.apache.log4j.Logger;
import org.joda.time.LocalDate;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.model.activities.AdministrativeActivity;
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.ScreenStatus;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUserRole;
import edu.harvard.med.screensaver.service.OperationRestrictedException;
import edu.harvard.med.screensaver.service.ServiceMessages;
import edu.harvard.med.screensaver.util.Pair;

/**
 * The Screen Expiration Service is used to adjust the DataSharingLevel of the Screen.  Screens that are more restrictive have 
 * the ScreenDataSharingLevel of "shared" or "mutual" sharing levels.  These more restrictive Screens are subject expiration of 
 * this privacy to the "mutual" level after an expiration period. <br>
 * The expiration period is calculated as the "ageToExpireFromActivityDateInDays" days since the last Screening (Lab) Activity 
 * for a Screen.  
 * <ul>
 * <li>The calculated expiration date will be stored in the Screen.dataPrivacyExpirationDate (DPED).  The DPED is set 
 * independently, using this updater, from a batch process.  
 * <li>Independently, other batch process will use this service: 
 * <li>to query for Screens that will be expiring in a certain period, in order to notify concerned parties
 * <li>to query for Screens that have had a publication (as this is an indicator that the privacy should be manually expired).
 * <li>to expire those Screens that should expire, as indicated by a DPED that has passed. 
 * @author sde4
 */
public class ScreenDataSharingLevelUpdater {
    private static Logger log = Logger.getLogger(ScreenDataSharingLevelUpdater.class);
    private GenericEntityDAO _dao;
    private ServiceMessages _messages;
    private boolean testMode = false;

    protected ScreenDataSharingLevelUpdater() {
    }

    public ScreenDataSharingLevelUpdater(GenericEntityDAO dao, ServiceMessages serviceMessages) {
        _dao = dao;
        _messages = serviceMessages;
    }

    @Transactional
    public AdministrativeActivity updateScreen(Screen screen, ScreenDataSharingLevel screenDataSharingLevel,
            AdministratorUser recordedBy) {
        recordedBy = _dao.reloadEntity(recordedBy);
        verifyOperationPermitted(recordedBy);
        ScreenDataSharingLevel oldLevel = screen.getDataSharingLevel();
        screen.setDataSharingLevel(screenDataSharingLevel);
        return screen.createUpdateActivity(recordedBy,
                "Data Sharing Level updated from : " + oldLevel + " to  " + screenDataSharingLevel);
    }

    /**
     * Returns a unique list of Small Molecule Screens that:
     * <ul>
     * <li>have ScreenResults
     * <li>have ScreenDataSharingLevel that is more restrictive than {@link ScreenDataSharingLevel#MUTUAL_SCREENS}
     * <li>have a {@link Screen#getDataPrivacyExpirationDate()} on or before the expireDate
     * <li>do not have a status of {@link ScreenStatus#DROPPED_TECHNICAL} or
     * {@link ScreenStatus#TRANSFERRED_TO_BROAD_INSTITUTE}
     * 
     * @param expireDate
     * @return not null, empty Set if nothing is found
     */
    public List<Screen> findNewExpiredNotNotified(LocalDate expireDate, ScreenType screenType) {
        String hql = "select distinct(s) from Screen s " + " join s.screenResult sr " + " where"
                + " s.dataPrivacyExpirationDate <= ? " + " and s.dataSharingLevel > ? " + " and s.screenType = ? "
                + " and s.dataPrivacyExpirationNotifiedDate is null" +
                //        " and s.screenId not in (select s.screenId from Screen s join s.statusItems si where si.status in ( ?, ? ) and si.screen = s ) "
                " and s.screenId not in (select s2.screenId from Screen s2 join s2.statusItems si where si.status in ( ?, ? ) and s2=s ) "
                + " order by s.screenId";
        List<Screen> list = _dao.findEntitiesByHql(Screen.class, hql, expireDate,
                ScreenDataSharingLevel.MUTUAL_SCREENS, screenType, ScreenStatus.DROPPED_TECHNICAL,
                ScreenStatus.TRANSFERRED_TO_BROAD_INSTITUTE);
        log.info("Hql: " + hql + ", " + list.size());
        return list;
    }

    public List<Screen> findExpired(LocalDate expireDate, ScreenType screenType) {
        String hql = "select distinct(s) from Screen s " + " join s.screenResult sr " + " where"
                + " s.dataPrivacyExpirationDate <= ? " + " and s.dataSharingLevel > ? " + " and s.screenType = ? "
                + " and s.screenId not in (select s2.screenId from Screen s2 join s2.statusItems si where si.status in ( ?, ? ) and s2=s ) "
                + " order by s.screenId";
        List<Screen> list = _dao.findEntitiesByHql(Screen.class, hql, expireDate,
                ScreenDataSharingLevel.MUTUAL_SCREENS, screenType, ScreenStatus.DROPPED_TECHNICAL,
                ScreenStatus.TRANSFERRED_TO_BROAD_INSTITUTE);
        log.info("Hql: " + hql + ", " + list.size());
        return list;
    }

    /**
     * For Screens that:
     * <ul>
     * <li>have ScreenResults
     * <li>have ScreenDataSharingLevel that is more restrictive than {@link ScreenDataSharingLevel#MUTUAL_SCREENS}
     * <li>have a {@link Screen#getDataPrivacyExpirationDate()} on or before the expireDate
     * <li>do not have a status of {@link ScreenStatus#DROPPED_TECHNICAL} or {@link ScreenStatus#TRANSFERRED_TO_BROAD_INSTITUTE}
     * </ul>
     * Expire any Screen returned from {@link ScreenDataSharingLevelUpdater#findNewExpiredNotNotified(LocalDate)} wherein the 
     * {@link Screen#getDataPrivacyExpirationDate()} is less than or equal to the passed in date.
     * @param date
     * @return Screens updated
     */
    @Transactional
    public List<Pair<Screen, AdministrativeActivity>> expireScreenDataSharingLevels(LocalDate date,
            AdministratorUser recordedBy, ScreenType screenType) {
        verifyOperationPermitted(recordedBy);
        List<Screen> screens = findExpired(date, screenType);
        List<Pair<Screen, AdministrativeActivity>> results = Lists.newLinkedList();
        for (Screen screen : screens) {
            assert (screen.getDataPrivacyExpirationDate().compareTo(date) <= 0);
            AdministrativeActivity activity = updateScreen(screen, ScreenDataSharingLevel.MUTUAL_SCREENS,
                    recordedBy);
            results.add(new Pair<Screen, AdministrativeActivity>(screen, activity));
        }
        return results;
    }

    public static class DataPrivacyAdjustment {
        public boolean isEmpty(boolean considerOverrides) {
            return (screensAdjusted.isEmpty() && screensAdjustedToAllowed.isEmpty() && !considerOverrides)
                    || (screensAdjusted.isEmpty() && screensAdjustedToAllowed.isEmpty() && considerOverrides
                            && screenPrivacyAdjustmentNotAllowed.isEmpty());
        }

        public List<Pair<Screen, AdministrativeActivity>> screensAdjusted = Lists.newLinkedList();
        public List<Pair<Screen, AdministrativeActivity>> screensAdjustedToAllowed = Lists.newLinkedList();
        public List<Pair<Screen, String>> screenPrivacyAdjustmentNotAllowed = Lists.newLinkedList();
    }

    /**
     * For Screens that:
     * <ul>
     * <li>have ScreenResults
     * <li>have ScreenDataSharingLevel that is more restrictive than {@link ScreenDataSharingLevel#MUTUAL_SCREENS}
     * <li>have a {@link Screen#getDataPrivacyExpirationDate()} on or before the expireDate
     * <li>do not have a status of {@link ScreenStatus#DROPPED_TECHNICAL} or {@link ScreenStatus#TRANSFERRED_TO_BROAD_INSTITUTE}
     * </ul>
     * This method invokes {@link Screen#setDataPrivacyExpirationDate(LocalDate)} with a value that is ageToExpireFromActivityDateInDays
     * days from the latest LabActivity (by date) for the Screen.  
     * @param ageToExpireFromActivityDateInDays the expiration period, in days
     * @param admin user performing
     * @return List<Screen, Pair<Admin-activity-if-any, message-if-no-action> >
     */
    @Transactional
    public DataPrivacyAdjustment adjustDataPrivacyExpirationByActivities(int ageToExpireFromActivityDateInDays,
            AdministratorUser admin, ScreenType screenType) {
        admin = _dao.reloadEntity(admin);
        String hql = "select distinct(s) from Screen as s " + " join s.screenResult sr "
                + " inner join s.labActivities la " + " where " + " s.screenType = ? "
                + " and s.dataSharingLevel > ? "
                + " and s.screenId not in (select s2.screenId from Screen s2 join s2.statusItems si where si.status in ( ?, ? ) and s2=s ) "
                + " order by s.screenId";

        List<Screen> screens = _dao.findEntitiesByHql(Screen.class, hql, screenType,
                ScreenDataSharingLevel.MUTUAL_SCREENS, ScreenStatus.DROPPED_TECHNICAL,
                ScreenStatus.TRANSFERRED_TO_BROAD_INSTITUTE);

        // Note, have to iterate in code to examine the date values as a suitable date arithmetic method was not determined for the HQL - sde4

        DataPrivacyAdjustment dataPrivacyAdjustment = new DataPrivacyAdjustment();

        for (Screen s : screens) {
            // note that getLabActivities does a "natural" sort, and that the comparator for the LabActivity uses the dateOfActivity to sort.

            SortedSet<LibraryScreening> libraryScreenings = s.getLabActivitiesOfType(LibraryScreening.class);
            if (libraryScreenings.isEmpty()) {
                log.debug("No LibraryScreenings for the screen: " + s);
            } else {
                //for [#2285] - don't consider Library Screenings of user provided plates 
                for (Iterator<LibraryScreening> iter = libraryScreenings.iterator(); iter.hasNext();) {
                    if (iter.next().isForExternalLibraryPlates())
                        iter.remove();
                }
                LibraryScreening libraryScreening = libraryScreenings.last();

                LocalDate requestedDate = libraryScreening.getDateOfActivity()
                        .plusDays(ageToExpireFromActivityDateInDays);
                LocalDate currentExpiration = s.getDataPrivacyExpirationDate();

                if (currentExpiration != null && currentExpiration.equals(requestedDate)) {
                    log.info("DataPrivacyExpirationDate is already set to the correct value for screen number: "
                            + s.getFacilityId());
                } else {
                    s.setDataPrivacyExpirationDate(requestedDate);
                    LocalDate setDate = s.getDataPrivacyExpirationDate();

                    AdministrativeActivity adminActivity = null;

                    if (currentExpiration != null && currentExpiration.equals(setDate)) {
                        // adjustment not allowed - overridden
                        String msg = _messages.getMessage(
                                "admin.screens.dataPrivacyExpiration.dataPrivacyExpirationdate.adjustment.adjustmentNotAllowed.comment",
                                currentExpiration, libraryScreening.getDateOfActivity(), requestedDate);

                        dataPrivacyAdjustment.screenPrivacyAdjustmentNotAllowed.add(Pair.newPair(s, msg));
                    } else {
                        if (!requestedDate.equals(setDate)) {
                            // adjustment allowed - but overridden to...
                            String msg = _messages.getMessage(
                                    "admin.screens.dataPrivacyExpiration.dataPrivacyExpirationdate.adjustment.adjustedBasedOnAllowed.comment",
                                    currentExpiration, libraryScreening.getDateOfActivity(), requestedDate,
                                    setDate);
                            adminActivity = s.createUpdateActivity(admin, msg);
                            dataPrivacyAdjustment.screensAdjustedToAllowed.add(Pair.newPair(s, adminActivity));
                        } else {
                            // adjustment allowed
                            String msg = _messages.getMessage(
                                    "admin.screens.dataPrivacyExpiration.dataPrivacyExpirationdate.adjustment.basedOnActivity.comment",
                                    currentExpiration, libraryScreening.getDateOfActivity(), setDate);
                            adminActivity = s.createUpdateActivity(admin, msg);
                            dataPrivacyAdjustment.screensAdjusted.add(Pair.newPair(s, adminActivity));
                        }
                        // we null the notified date, since it should be re-notified -sde4
                        s.setDataPrivacyExpirationNotifiedDate(null);
                    }
                }
            }
        }
        log.info("adjustDataPrivacyExpirationByActivities, " + " adjusted: "
                + dataPrivacyAdjustment.screensAdjusted.size() + " adjusted to allowed: "
                + dataPrivacyAdjustment.screensAdjustedToAllowed.size() + ", adjustment not allowed: "
                + dataPrivacyAdjustment.screenPrivacyAdjustmentNotAllowed.size());
        return dataPrivacyAdjustment;
    }

    /**
     * Find Screens that:
     * <ul>
     * <li>have Publications
     * <li>have ScreenResults
     * <li>have ScreenDataSharingLevel that is more restrictive than {@link ScreenDataSharingLevel#MUTUAL_SCREENS}
     * <li>have a {@link Screen#getDataPrivacyExpirationDate()} on or before the expireDate
     * <li>do not have a status of {@link ScreenStatus#DROPPED_TECHNICAL} or {@link ScreenStatus#TRANSFERRED_TO_BROAD_INSTITUTE}
     * </ul>
     */
    public List<Screen> findNewPublishedPrivate(ScreenType screenType) {
        String hql = "select distinct (s) from Screen as s " + " join s.publications " + " join s.screenResult sr "
                + " where s.dataSharingLevel > ? " + " and s.screenType = ? "
                + " and s.screenId not in (select s2.screenId from Screen s2 join s2.statusItems si where si.status in ( ?, ? ) and s2=s ) "
                + " order by s.screenId";
        return _dao.findEntitiesByHql(Screen.class, hql, ScreenDataSharingLevel.SHARED, screenType,
                ScreenStatus.DROPPED_TECHNICAL, ScreenStatus.TRANSFERRED_TO_BROAD_INSTITUTE);
    }

    @Transactional
    public void setDataPrivacyExpirationNotifiedDate(Screen screen) {
        screen.setDataPrivacyExpirationNotifiedDate(new LocalDate());
        _dao.saveOrUpdateEntity(screen);
    }

    private void verifyOperationPermitted(AdministratorUser recordedBy) throws OperationRestrictedException {
        if (!!!recordedBy.getScreensaverUserRoles()
                .contains(ScreensaverUserRole.SCREEN_DATA_SHARING_LEVELS_ADMIN)) {
            throw new OperationRestrictedException("to update a Screen data sharing level, administrator must have "
                    + ScreensaverUserRole.SCREEN_DATA_SHARING_LEVELS_ADMIN.getDisplayableRoleName() + " role");
        }
    }

    public Set<ScreensaverUser> findDataSharingLevelAdminUsers() {
        String hql = "from ScreensaverUser where ? in elements (screensaverUserRoles)";
        return Sets.newHashSet(_dao.findEntitiesByHql(ScreensaverUser.class, hql,
                ScreensaverUserRole.SCREEN_DSL_EXPIRATION_NOTIFY.getRoleName()));
    }
}