org.kuali.kra.protocol.actions.reviewcomments.ReviewCommentsServiceImplBase.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.kra.protocol.actions.reviewcomments.ReviewCommentsServiceImplBase.java

Source

/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 * 
 * Copyright 2005-2015 Kuali, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kra.protocol.actions.reviewcomments;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.kuali.coeus.common.committee.impl.bo.CommitteeBase;
import org.kuali.coeus.common.committee.impl.bo.CommitteeMembershipBase;
import org.kuali.coeus.common.committee.impl.bo.CommitteeScheduleBase;
import org.kuali.coeus.common.committee.impl.meeting.CommitteeScheduleMinuteBase;
import org.kuali.coeus.common.committee.impl.meeting.MinuteEntryType;
import org.kuali.coeus.common.committee.impl.service.CommitteeServiceBase;
import org.kuali.coeus.common.framework.attachment.AttachmentFile;
import org.kuali.coeus.common.framework.person.KcPerson;
import org.kuali.coeus.common.framework.person.KcPersonService;
import org.kuali.coeus.sys.framework.service.KcServiceLocator;
import org.kuali.kra.infrastructure.RoleConstants;
import org.kuali.kra.kim.bo.KcKimAttributes;
import org.kuali.kra.protocol.ProtocolBase;
import org.kuali.kra.protocol.ProtocolDocumentBase;
import org.kuali.kra.protocol.ProtocolFinderDao;
import org.kuali.kra.protocol.actions.submit.ProtocolReviewer;
import org.kuali.kra.protocol.actions.submit.ProtocolSubmissionBase;
import org.kuali.kra.protocol.onlinereview.ProtocolOnlineReviewBase;
import org.kuali.kra.protocol.onlinereview.ProtocolReviewAttachmentBase;
import org.kuali.kra.protocol.onlinereview.ProtocolReviewableBase;
import org.kuali.kra.protocol.personnel.ProtocolPersonBase;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kim.api.identity.Person;
import org.kuali.rice.kim.api.role.RoleService;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.util.GlobalVariables;

import java.util.*;

public abstract class ReviewCommentsServiceImplBase<PRA extends ProtocolReviewAttachmentBase>
        implements ReviewCommentsService<PRA> {

    private static final String HIDE = "0";
    private static final String DISPLAY = "1";
    protected BusinessObjectService businessObjectService;
    private CommitteeServiceBase committeeService;
    private ProtocolFinderDao protocolFinderDao;
    private RoleService roleService;
    private DateTimeService dateTimeService;
    private ParameterService parameterService;
    private KcPersonService kcPersonService;
    private Set<String> adminIds;
    private List<String> adminUserNames;
    private List<String> reviewerIds;
    private Set<String> viewerIds;
    private Set<String> aggregatorIds;
    private boolean displayReviewerNameToPersonnel;
    private boolean displayReviewerNameToReviewers;
    private boolean displayReviewerNameToActiveMembers;

    @Override
    public boolean canViewOnlineReviewerComments(String principalId, ProtocolSubmissionBase protocolSubmission) {
        return isAdminOrOnlineReviewer(principalId, protocolSubmission)
                || hasSubmissionCompleteStatus(protocolSubmission)
                || isActiveCommitteeMember(protocolSubmission, principalId);
    }

    @Override
    public boolean canViewOnlineReviewers(String principalId, ProtocolSubmissionBase protocolSubmission) {
        return isAdminOrOnlineReviewer(principalId, protocolSubmission);
    }

    private boolean isAdminOrOnlineReviewer(String principalId, ProtocolSubmissionBase submission) {
        boolean isAdmin = false;
        boolean isReviewer = false;

        Collection<String> ids = roleService.getRoleMemberPrincipalIds(RoleConstants.DEPARTMENT_ROLE_TYPE,
                getAdministratorRoleHook(), null);
        isAdmin = ids.contains(principalId);

        if (principalId != null) {
            List<ProtocolReviewer> reviewers = submission.getProtocolReviewers();
            for (ProtocolReviewer reviewer : reviewers) {
                if (StringUtils.equals(principalId, reviewer.getPersonId())) {
                    isReviewer = true;
                    break;
                }
            }
        }

        return isAdmin || isReviewer;
    }

    private boolean hasSubmissionCompleteStatus(ProtocolSubmissionBase submission) {
        boolean validSubmissionStatus = Arrays.asList(getProtocolSubmissionCompleteStatusCodeArrayHook())
                .contains(submission.getSubmissionStatusCode());
        return validSubmissionStatus;
    }

    protected abstract String[] getProtocolSubmissionCompleteStatusCodeArrayHook();

    public List<CommitteeScheduleMinuteBase> getReviewerComments(String protocolNumber, int submissionNumber) {
        ArrayList<CommitteeScheduleMinuteBase> reviewComments = new ArrayList<CommitteeScheduleMinuteBase>();

        List<ProtocolSubmissionBase> protocolSubmissions = protocolFinderDao.findProtocolSubmissions(protocolNumber,
                submissionNumber);

        for (ProtocolSubmissionBase protocolSubmission : protocolSubmissions) {
            if (protocolSubmission.getCommitteeScheduleMinutes() != null) {
                // search table directly as ProtocolBase Submission is not refreshed as commit happens later
                Map fieldValues = new HashMap();
                fieldValues.put("protocolIdFk", protocolSubmission.getProtocolId());
                fieldValues.put("submissionIdFk", protocolSubmission.getSubmissionId());

                List<CommitteeScheduleMinuteBase> reviewComments1 = (List<CommitteeScheduleMinuteBase>) businessObjectService
                        .findMatchingOrderBy(getCommitteeScheduleMinuteBOClassHook(), fieldValues,
                                "commScheduleMinutesId", false);
                for (CommitteeScheduleMinuteBase minute : reviewComments1) {
                    String minuteEntryTypeCode = minute.getMinuteEntryTypeCode();
                    // need to check current minute entry; otherwise may have minutes from previous version comittee
                    if ((MinuteEntryType.PROTOCOL.equals(minuteEntryTypeCode)
                            || MinuteEntryType.PROTOCOL_REVIEWER_COMMENT.equals(minuteEntryTypeCode))
                            && isCurrentMinuteEntry(minute)) {
                        if (getReviewerCommentsView(minute)) {
                            reviewComments.add(minute);
                        }
                    }
                }
            }
        }

        return reviewComments;
    }

    protected abstract Class<? extends CommitteeScheduleMinuteBase> getCommitteeScheduleMinuteBOClassHook();

    @Override
    public List<PRA> getReviewerAttachments(String protocolNumber, int submissionNumber) {

        List<PRA> reviewAttachments = new ArrayList<PRA>();
        List<ProtocolSubmissionBase> protocolSubmissions = protocolFinderDao.findProtocolSubmissions(protocolNumber,
                submissionNumber);
        // protocol versioning does not version review attachments/comments
        for (ProtocolSubmissionBase protocolSubmission : protocolSubmissions) {
            if (CollectionUtils.isNotEmpty(protocolSubmission.getReviewAttachments())
                    || protocolSubmissions.size() == 1) {
                // search table directly as ProtocolBase Submission is not refreshed as commit happens later
                Map fieldValues = new HashMap();
                fieldValues.put("protocolIdFk", protocolSubmission.getProtocolId());
                fieldValues.put("submissionIdFk", protocolSubmission.getSubmissionId());
                List<PRA> reviewAttachments1 = (List<PRA>) businessObjectService.findMatchingOrderBy(
                        getProtocolReviewAttachmentClassHook(), fieldValues, "attachmentId", false);

                for (ProtocolReviewAttachmentBase reviewAttachment : reviewAttachments1) {
                    if (getReviewerCommentsView(reviewAttachment)) {
                        reviewAttachments.add((PRA) reviewAttachment);
                    }
                }
            }
        }
        return reviewAttachments;
    }

    @Override
    public List<ProtocolReviewer> getProtocolReviewers(String protocolNumber, int submissionNumber) {
        List<ProtocolReviewer> reviewers = new ArrayList<ProtocolReviewer>();
        List<ProtocolSubmissionBase> protocolSubmissions = protocolFinderDao.findProtocolSubmissions(protocolNumber,
                submissionNumber);
        for (ProtocolSubmissionBase protocolSubmission : protocolSubmissions) {
            reviewers.addAll(protocolSubmission.getProtocolReviewers());
        }
        return reviewers;
    }

    @Override
    public List<ProtocolOnlineReviewBase> getProtocolOnlineReviews(String protocolNumber, int submissionNumber) {
        List<ProtocolOnlineReviewBase> activeReviews = new ArrayList<ProtocolOnlineReviewBase>();
        List<ProtocolSubmissionBase> protocolSubmissions = protocolFinderDao.findProtocolSubmissions(protocolNumber,
                submissionNumber);
        for (ProtocolSubmissionBase protocolSubmission : protocolSubmissions) {
            activeReviews.addAll(protocolSubmission.getActiveProtocolOnlineReviews());
        }
        return activeReviews;
    }

    /*
     * when version committee, the minutes also versioned. This is to get the current one.
     */
    protected boolean isCurrentMinuteEntry(CommitteeScheduleMinuteBase minute) {
        minute.refreshReferenceObject("committeeSchedule");
        if (minute.getCommitteeSchedule() != null) {
            CommitteeBase committee = committeeService
                    .getCommitteeById(minute.getCommitteeSchedule().getParentCommittee().getCommitteeId());
            return committee.getId().equals(minute.getCommitteeSchedule().getParentCommittee().getId());
        } else {
            // if scheduleid is 999999999
            return true;
        }
    }

    public void addReviewComment(CommitteeScheduleMinuteBase newReviewComment,
            List<CommitteeScheduleMinuteBase> reviewComments, ProtocolBase protocol) {
        ProtocolSubmissionBase protocolSubmission = getSubmission(protocol);
        if (protocolSubmission.getScheduleIdFk() != null) {
            newReviewComment.setScheduleIdFk(protocolSubmission.getScheduleIdFk());
        } else {
            newReviewComment.setScheduleIdFk(CommitteeScheduleBase.DEFAULT_SCHEDULE_ID);
        }
        newReviewComment.setEntryNumber(reviewComments.size());
        newReviewComment.setProtocolIdFk(protocol.getProtocolId());
        newReviewComment.setProtocol(protocol);
        newReviewComment.setSubmissionIdFk(protocolSubmission.getSubmissionId());
        newReviewComment.setCreateUser(GlobalVariables.getUserSession().getPrincipalName());
        newReviewComment.setCreateTimestamp(dateTimeService.getCurrentTimestamp());
        newReviewComment.setUpdateUser(GlobalVariables.getUserSession().getPrincipalName());
        // TO show update timestamp after 'add'
        newReviewComment.setUpdateTimestamp(dateTimeService.getCurrentTimestamp());

        reviewComments.add(newReviewComment);
    }

    public void addReviewComment(CommitteeScheduleMinuteBase newReviewComment,
            List<CommitteeScheduleMinuteBase> reviewComments, ProtocolOnlineReviewBase protocolOnlineReview) {
        newReviewComment.setProtocolOnlineReview(protocolOnlineReview);
        newReviewComment.setProtocolOnlineReviewIdFk(protocolOnlineReview.getProtocolOnlineReviewId());
        newReviewComment.setProtocolReviewer(protocolOnlineReview.getProtocolReviewer());
        newReviewComment.setProtocolReviewerIdFk(protocolOnlineReview.getProtocolReviewerId());
        addReviewComment(newReviewComment, reviewComments, protocolOnlineReview.getProtocol());
    }

    public void moveUpReviewComment(List<CommitteeScheduleMinuteBase> reviewComments, ProtocolBase protocol,
            int fromIndex) {
        if (fromIndex > 0) {
            int toIndex = indexOfPreviousProtocolReviewComment(reviewComments, protocol, fromIndex);
            if (toIndex < fromIndex) {
                CommitteeScheduleMinuteBase movingReviewComment = reviewComments.remove(fromIndex);
                reviewComments.add(toIndex, movingReviewComment);
                for (int i = toIndex; i <= fromIndex; i++) {
                    reviewComments.get(i).setEntryNumber(i);
                }
            }
        }
    }

    /**
     * Returns the index of the review comment just before to the one at index, where both of the review comments are in the same
     * protocol.
     * 
     * If there is no such review comment, returns the index of the review comment at index.
     * 
     * @param reviewComments the list of review comments
     * @param protocol the current protocol
     * @param currentIndex the index of the current review comment
     * @return the index of the previous review comment, or the same index if there is none
     */
    private int indexOfPreviousProtocolReviewComment(List<CommitteeScheduleMinuteBase> reviewComments,
            ProtocolBase protocol, int currentIndex) {
        int previousIndex = currentIndex;

        for (ListIterator<CommitteeScheduleMinuteBase> iterator = reviewComments
                .listIterator(currentIndex); iterator.hasPrevious();) {
            int iteratorIndex = iterator.previousIndex();
            CommitteeScheduleMinuteBase currentReviewComment = iterator.previous();
            if (ObjectUtils.equals(currentReviewComment.getProtocolId(), protocol.getProtocolId())) {
                previousIndex = iteratorIndex;
                break;
            }
        }

        return previousIndex;
    }

    public void moveDownReviewComment(List<CommitteeScheduleMinuteBase> reviewComments, ProtocolBase protocol,
            int fromIndex) {
        if (fromIndex < reviewComments.size() - 1) {
            int toIndex = indexOfNextProtocolReviewComment(reviewComments, protocol, fromIndex);
            if (toIndex > fromIndex) {
                CommitteeScheduleMinuteBase movingReviewComment = reviewComments.remove(fromIndex);
                reviewComments.add(toIndex, movingReviewComment);
                for (int i = fromIndex; i <= toIndex; i++) {
                    reviewComments.get(i).setEntryNumber(i);
                }
            }
        }
    }

    /**
     * Returns whether the current user can view this comment.
     * 
     * This is true either if 1) The current user has the role IRB Administrator 2) The comment/minute has been accepted by an IRB
     * Administrator and one of the following conditions is true: 3) The current user does not have the role IRB Administrator, but
     * the current user is the comment creator 4) The current user does not have the role IRB Administrator, but is a reviewer of
     * the protocol, and not part of the protocol personnel, and the comment is final 5) The current user does not have the role IRB
     * Administrator, but is an active committee member, and not part of the protocol personnel, and the comment is final 6) The
     * comment is public and final
     * 
     * In addition if the comment is not associated with an online review then it automatically returns true.
     * 
     * @param CommitteeScheduleMinuteBase minute
     * @return whether the current user can view this comment
     */
    public boolean getReviewerCommentsView(ProtocolReviewableBase minute) {
        String principalId = GlobalVariables.getUserSession().getPrincipalId();
        String principalName = GlobalVariables.getUserSession().getPrincipalName();

        if (isAdministrator(principalId)) {
            return true;
        } else {
            if (minute.getProtocolOnlineReviewIdFk() != null) {
                // this comment originated via an OLR, so check first that it is accepted and then that it 
                // is either created by current user or 'isViewable' for the current user
                if (minute.isAccepted()) {
                    return StringUtils.equals(principalName, minute.getCreateUser()) || isViewable(minute);
                } else {
                    return false;
                }
            } else {
                // this comment did not originate in an OLR (most probably added by admin via some non-OLR comments interface), 
                // so check that it 'isViewable' for the current user
                return isViewable(minute);
            }
        }
    }

    /*
     * This method is to check if review comment/attachment is viewable for this user
     */
    private boolean isViewable(ProtocolReviewableBase reviewable) {
        String principalId = GlobalVariables.getUserSession().getPrincipalId();
        return reviewable.isFinal() && (!reviewable.isPrivate()
                || ((isReviewer(reviewable, principalId) || isActiveCommitteeMember(reviewable, principalId))
                        && (!isProtocolPersonnel(reviewable, principalId)
                                && !hasProtocolPermission(reviewable, principalId))));
    }

    private boolean isAdministrator(String principalId) {
        RoleService roleService = KcServiceLocator.getService(RoleService.class);
        Collection<String> ids = roleService.getRoleMemberPrincipalIds(RoleConstants.DEPARTMENT_ROLE_TYPE,
                getAdministratorRoleHook(), null);
        return ids.contains(principalId);
    }

    protected abstract String getAdministratorRoleHook();

    /**
     * Returns the index of the review comment just after to the one at index, where both of the review comments are in the same
     * protocol.
     * 
     * If there is no such review comment, returns the index of the review comment at index.
     * 
     * @param reviewComments the list of review comments
     * @param protocol the current protocol
     * @param currentIndex the index of the current review comment
     * @return the index of the next review comment, or the same index if there is none
     */
    private int indexOfNextProtocolReviewComment(List<CommitteeScheduleMinuteBase> reviewComments,
            ProtocolBase protocol, int currentIndex) {
        int nextIndex = currentIndex;

        for (ListIterator<CommitteeScheduleMinuteBase> iterator = reviewComments
                .listIterator(currentIndex + 1); iterator.hasNext();) {
            int iteratorIndex = iterator.nextIndex();
            CommitteeScheduleMinuteBase currentReviewComment = iterator.next();
            if (ObjectUtils.equals(currentReviewComment.getProtocolId(), protocol.getProtocolId())) {
                nextIndex = iteratorIndex;
                break;
            }
        }

        return nextIndex;
    }

    public void deleteReviewComment(List<CommitteeScheduleMinuteBase> reviewComments, int index,
            List<CommitteeScheduleMinuteBase> deletedReviewComments) {
        if (index >= 0 && index < reviewComments.size()) {
            CommitteeScheduleMinuteBase reviewComment = reviewComments.get(index);
            if (reviewComment.getCommScheduleMinutesId() != null) {
                deletedReviewComments.add(reviewComment);
            }
            reviewComments.remove(index);

            for (int i = index; i < reviewComments.size(); i++) {
                reviewComments.get(i).setEntryNumber(i);
            }
        }
    }

    public void deleteAllReviewComments(List<CommitteeScheduleMinuteBase> reviewComments,
            List<CommitteeScheduleMinuteBase> deletedReviewComments) {
        for (CommitteeScheduleMinuteBase reviewerComment : reviewComments) {
            if (reviewerComment.getCommScheduleMinutesId() != null) {
                deletedReviewComments.add(reviewerComment);
            }
        }
        reviewComments.clear();
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void saveReviewComments(List<CommitteeScheduleMinuteBase> reviewComments,
            List<CommitteeScheduleMinuteBase> deletedReviewComments) {
        for (CommitteeScheduleMinuteBase reviewComment : reviewComments) {
            boolean doUpdate = true;
            if (reviewComment.getCommScheduleMinutesId() != null) {
                CommitteeScheduleMinuteBase pristineInstance = reviewComment.getPristineInstance();
                if ((pristineInstance != null) && (!reviewComment.equals(pristineInstance))) {
                    doUpdate = true;
                    // we update the user name only if certain important fields have changed
                    if (reviewComment.isUpdateUserToBeRecorded(pristineInstance)) {
                        KcPerson kcPerson = KcServiceLocator.getService(KcPersonService.class)
                                .getKcPersonByPersonId(
                                        GlobalVariables.getUserSession().getPerson().getPrincipalId());
                        reviewComment.setUpdateUserFullName(kcPerson.getFullName());
                    }
                } else {
                    doUpdate = false;
                }
            }
            if (doUpdate) {
                businessObjectService.save(reviewComment);
            }
        }

        if (!deletedReviewComments.isEmpty()) {
            businessObjectService.delete(deletedReviewComments);
        }
    }

    protected abstract ProtocolSubmissionBase getSubmission(ProtocolBase protocol);

    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
        this.businessObjectService = businessObjectService;
    }

    public void setCommitteeService(CommitteeServiceBase committeeService) {
        this.committeeService = committeeService;
    }

    /*
     * TODO: abstracted out during iacuc refactoring
     */
    public void setProtocolFinderDao(ProtocolFinderDao protocolFinderDao) {
        this.protocolFinderDao = protocolFinderDao;
    }

    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }

    public void setDateTimeService(DateTimeService dateTimeService) {
        this.dateTimeService = dateTimeService;
    }

    private void getReviewerNameParams() {
        displayReviewerNameToActiveMembers = isDisplayReviewerName(getDisplayRevNameToActiveCmtMembersHook());
        displayReviewerNameToPersonnel = isDisplayReviewerName(getDisplayRevNameToProtocolPersonnelHook());
        displayReviewerNameToReviewers = isDisplayReviewerName(getDisplayRevNameToReviewersHook());
    }

    protected abstract String getDisplayRevNameToActiveCmtMembersHook();

    protected abstract String getDisplayRevNameToProtocolPersonnelHook();

    protected abstract String getDisplayRevNameToReviewersHook();

    /*
     * retrieve Display reviewer name parameter and compre with 'HIDE'
     */
    private boolean isDisplayReviewerName(String paramName) {
        String param = parameterService.getParameterValueAsString(getProtocolDocumentBOClassHook(), paramName);
        return !StringUtils.equals(HIDE, param);
    }

    protected abstract Class<? extends ProtocolDocumentBase> getProtocolDocumentBOClassHook();

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    @Override
    public boolean setHideReviewerName(ProtocolBase protocol, int submissionNumber) {
        return setHideReviewerName(getReviewerComments(protocol.getProtocolNumber(), submissionNumber));
    }

    public boolean setHideReviewerName(List<? extends ProtocolReviewableBase> reviewComments) {
        boolean isHide = true;
        setReviewerIds(reviewerIds);
        getReviewerNameParams();
        for (ProtocolReviewableBase reviewComment : reviewComments) {
            if (canViewName(reviewComment)) {
                reviewComment.setDisplayReviewerName(true);
                isHide = false;
            }

        }
        return isHide;
    }

    public boolean isHidePrivateFinalFlagsForPI(List<? extends ProtocolReviewableBase> reviewComments) {
        boolean isHide = false;
        String principalId = GlobalVariables.getUserSession().getPrincipalId();
        for (ProtocolReviewableBase reviewComment : reviewComments) {
            if (isProtocolPersonnel(reviewComment, principalId) && getReviewerCommentsView(reviewComment)) {
                isHide = true;
                break;
            }
        }
        return isHide;
    }

    public boolean setHideViewButton(List<PRA> reviewAttachments) {
        boolean isHide = true;
        getReviewerNameParams();
        String principalId = GlobalVariables.getUserSession().getPrincipalId();
        for (PRA reviewAttachment : reviewAttachments) {
            if (!reviewAttachment.isPrivateFlag() || !isProtocolPersonnel(reviewAttachment, principalId)) {
                reviewAttachment.setDisplayViewButton(true);
                isHide = false;
            }

        }
        return isHide;
    }

    private boolean canViewName(ProtocolReviewableBase reviewComment) {
        boolean canViewName = false;
        Person person = GlobalVariables.getUserSession().getPerson();
        if (isAdmin(person.getPrincipalId()) || isCreator(reviewComment, person.getPrincipalName())) {
            canViewName = true;
        } else {
            // if protocol personnel, then only if display to personnel is set to true
            if (isProtocolPersonnelOrHasProtocolRole(reviewComment)) {
                if (isDisplayReviewerNameToPersonnel()) {
                    canViewName = true;
                }
            }
            // must be non protocol personnel
            else if ((isDisplayReviewerNameToReviewers() && isReviewer(reviewComment, person.getPrincipalId()))
                    || (isDisplayReviewerNameToActiveMembers()
                            && getActiveMemberId(reviewComment).contains(person.getPrincipalId()))) {
                // only if display to personnel is true or is not protocol personnel
                canViewName = true;
            }

        }
        return canViewName;
    }

    private boolean hasProtocolPermission(ProtocolReviewableBase reviewComment, String principalId) {
        return getProtocolAggregators(reviewComment).contains(principalId)
                || getProtocolViewers(reviewComment).contains(principalId);
    }

    private boolean isProtocolPersonnel(ProtocolReviewableBase reviewComment, String principalId) {
        return getPersonnelIds(reviewComment).contains(principalId);
    }

    /*
     * check if user is protocol personnel or has permission as aggregator or viewer
     */
    private boolean isProtocolPersonnelOrHasProtocolRole(ProtocolReviewableBase reviewComment) {
        Person person = GlobalVariables.getUserSession().getPerson();
        return getPersonnelIds(reviewComment).contains(person.getPrincipalId())
                || getProtocolAggregators().contains(person.getPrincipalId())
                || getProtocolViewers().contains(person.getPrincipalId());
    }

    private List<String> getActiveMemberId(ProtocolReviewableBase reviewComment) {
        List<String> activeMemberIds = new ArrayList<String>();
        List<CommitteeMembershipBase> members = new ArrayList<CommitteeMembershipBase>();
        if (reviewComment.isReviewComment()) {
            members = ((CommitteeScheduleMinuteBase) reviewComment).getCommitteeSchedule().getParentCommittee()
                    .getCommitteeMemberships();
        } else {
            members = ((PRA) reviewComment).getProtocol().getProtocolSubmission().getCommittee()
                    .getCommitteeMemberships();
        }
        for (CommitteeMembershipBase member : members) {
            if (member.isActive()) {
                if (StringUtils.isNotBlank(member.getPersonId())) {
                    activeMemberIds.add(member.getPersonId());
                } else {
                    activeMemberIds.add(member.getRolodexId().toString());
                }
            }
        }
        return activeMemberIds;
    }

    private List<String> getPersonnelIds(ProtocolReviewableBase reviewComment) {
        List<String> PersonnelIds = new ArrayList<String>();
        if (reviewComment.getProtocol() != null) {
            for (ProtocolPersonBase person : reviewComment.getProtocol().getProtocolPersons()) {
                if (StringUtils.isNotBlank(person.getPersonId())) {
                    PersonnelIds.add(person.getPersonId());
                } else {
                    PersonnelIds.add(person.getRolodexId().toString());
                }
            }
        }
        return PersonnelIds;
    }

    private boolean isAdmin(String principalId) {
        return !CollectionUtils.isEmpty(getAdminIds()) && getAdminIds().contains(principalId);
    }

    /*
     * if the person a reviewer.
     */
    private boolean isReviewer(ProtocolReviewableBase reviewComment, String principalId) {
        List<String> reviewerIds = getProtocolReviewerIds(reviewComment);
        return !reviewerIds.isEmpty() && reviewerIds.contains(principalId);
    }

    /*
     * if the person is comment creator.
     */
    private boolean isCreator(ProtocolReviewableBase reviewComment, String userName) {
        return reviewComment.getCreateUser().equals(userName);
    }

    /*
     * get the reviewer ids for this submission
     */
    private List<String> getProtocolReviewerIds(ProtocolReviewableBase reviewComment) {
        List<String> reviewerIds = new ArrayList<String>();
        if (reviewComment.getProtocolId() != null) {
            // TODO : need to check if the submission number is ok to get this way
            reviewerIds = getProtocolReviewerIds(reviewComment.getProtocolId(),
                    reviewComment.getProtocol().getProtocolSubmission().getSubmissionNumber());
        }
        return reviewerIds;
    }

    /*
     * retrieve reviewer ids from db based on protocolid and submissionnumber
     */
    private List<String> getProtocolReviewerIds(Long protocolId, int submissionNumber) {
        Map fieldValues = new HashMap();
        fieldValues.put("protocolIdFk", protocolId);
        fieldValues.put("submissionNumber", submissionNumber);
        List<String> reviewerPersonIds = new ArrayList<String>();
        for (ProtocolReviewer reviewer : (List<ProtocolReviewer>) businessObjectService
                .findMatching(getProtocolReviewClassHook(), fieldValues)) {
            reviewerPersonIds.add(reviewer.getPersonId());
        }
        return reviewerPersonIds;

    }

    protected abstract Class<? extends ProtocolReviewer> getProtocolReviewClassHook();

    /*
     * retrieve admins from role table
     */
    private void populateAdmins() {
        adminIds = (Set<String>) roleService.getRoleMemberPrincipalIds("KC-UNT", getAdministratorRoleHook(), null);
        adminUserNames = new ArrayList<String>();
        for (String id : adminIds) {
            KcPerson kcPerson = kcPersonService.getKcPersonByPersonId(id);
            adminUserNames.add(kcPerson.getUserName());
        }
    }

    private Set<String> getProtocolAggregators() {
        if (CollectionUtils.isEmpty(aggregatorIds)) {
            aggregatorIds = (Set<String>) roleService.getRoleMemberPrincipalIds(getNamespaceHook(),
                    getAggregatorRoleNameHook(), null);

        }
        return aggregatorIds;

    }

    protected abstract String getNamespaceHook();

    protected abstract String getAggregatorRoleNameHook();

    private Set<String> getProtocolAggregators(ProtocolReviewableBase minute) {
        if (CollectionUtils.isEmpty(aggregatorIds) && minute != null) {

            aggregatorIds = new HashSet<String>();

            if (StringUtils.isNotBlank(minute.getProtocol().getProtocolNumber())) {
                Map<String, String> protocolAttr = new HashMap<String, String>();
                protocolAttr.put(KcKimAttributes.PROTOCOL, minute.getProtocol().getProtocolNumber());
                Set<String> protoResults = (Set<String>) roleService.getRoleMemberPrincipalIds(getNamespaceHook(),
                        getAggregatorRoleNameHook(), new HashMap<String, String>(protocolAttr));

                if (CollectionUtils.isNotEmpty(protoResults)) {
                    aggregatorIds.addAll(protoResults);
                }
            }

            if (StringUtils.isNotBlank(minute.getProtocol().getLeadUnitNumber())) {
                Map<String, String> leadUnitAttr = new HashMap<String, String>();
                leadUnitAttr.put(KcKimAttributes.UNIT_NUMBER, minute.getProtocol().getLeadUnitNumber());
                Set<String> leadUnitResults = (Set<String>) roleService.getRoleMemberPrincipalIds(
                        getNamespaceHook(), getAggregatorRoleNameHook(), new HashMap<String, String>(leadUnitAttr));

                if (CollectionUtils.isNotEmpty(leadUnitResults)) {
                    aggregatorIds.addAll(leadUnitResults);
                }
            }

        }

        return aggregatorIds;
    }

    private Set<String> getProtocolViewers() {
        if (CollectionUtils.isEmpty(viewerIds)) {
            viewerIds = (Set<String>) roleService.getRoleMemberPrincipalIds(getNamespaceHook(),
                    getProtocolViewerRoleNameHook(), null);

        }
        return viewerIds;

    }

    protected abstract String getProtocolViewerRoleNameHook();

    private Set<String> getProtocolViewers(ProtocolReviewableBase minute) {
        if (CollectionUtils.isEmpty(viewerIds) && minute != null) {

            viewerIds = new HashSet<String>();

            if (StringUtils.isNotBlank(minute.getProtocol().getProtocolNumber())) {
                Map<String, String> protocolAttr = new HashMap<String, String>();
                /*
                 * IS the kim attr data for iacuc also under 'protocol'?? not sure, need to verify that
                 */
                protocolAttr.put(KcKimAttributes.PROTOCOL, minute.getProtocol().getProtocolNumber());
                Set<String> protoResults = (Set<String>) roleService.getRoleMemberPrincipalIds(getNamespaceHook(),
                        getProtocolViewerRoleNameHook(), new HashMap<String, String>(protocolAttr));

                if (CollectionUtils.isNotEmpty(protoResults)) {
                    viewerIds.addAll(protoResults);
                }
            }

            if (StringUtils.isNotBlank(minute.getProtocol().getLeadUnitNumber())) {
                Map<String, String> leadUnitAttr = new HashMap<String, String>();
                leadUnitAttr.put(KcKimAttributes.UNIT_NUMBER, minute.getProtocol().getLeadUnitNumber());
                Set<String> leadUnitResults = (Set<String>) roleService.getRoleMemberPrincipalIds(
                        getNamespaceHook(), getProtocolViewerRoleNameHook(),
                        new HashMap<String, String>(leadUnitAttr));

                if (CollectionUtils.isNotEmpty(leadUnitResults)) {
                    viewerIds.addAll(leadUnitResults);
                }
            }
        }

        return viewerIds;

    }

    public void setKimRoleManagementService(RoleService kimRoleManagementService) {
        this.roleService = kimRoleManagementService;
    }

    public void setKcPersonService(KcPersonService kcPersonService) {
        this.kcPersonService = kcPersonService;
    }

    public Set<String> getAdminIds() {
        if (CollectionUtils.isEmpty(adminIds)) {
            populateAdmins();
        }
        return adminIds;
    }

    public void setAdminIds(Set<String> adminIds) {
        this.adminIds = adminIds;
    }

    public List<String> getAdminUserNames() {
        if (CollectionUtils.isEmpty(adminUserNames)) {
            populateAdmins();
        }
        return adminUserNames;
    }

    public void setAdminUserNames(List<String> adminUserNames) {
        this.adminUserNames = adminUserNames;
    }

    public List<String> getReviewerIds() {
        return reviewerIds;
    }

    public void setReviewerIds(List<String> reviewerIds) {
        this.reviewerIds = reviewerIds;
    }

    public boolean isDisplayReviewerNameToPersonnel() {
        return displayReviewerNameToPersonnel;
    }

    public void setDisplayReviewerNameToPersonnel(boolean displayReviewerNameToPersonnel) {
        this.displayReviewerNameToPersonnel = displayReviewerNameToPersonnel;
    }

    public boolean isDisplayReviewerNameToReviewers() {
        return displayReviewerNameToReviewers;
    }

    public void setDisplayReviewerNameToReviewers(boolean displayReviewerNameToReviewers) {
        this.displayReviewerNameToReviewers = displayReviewerNameToReviewers;
    }

    public boolean isDisplayReviewerNameToActiveMembers() {
        return displayReviewerNameToActiveMembers;
    }

    public void setDisplayReviewerNameToActiveMembers(boolean displayReviewerNameToActiveMembers) {
        this.displayReviewerNameToActiveMembers = displayReviewerNameToActiveMembers;
    }

    /**
     * 
     * This method determines if the current user is an active committee member
     * 
     * @param minute
     * @param principalId
     * @return true if and active committee member, false otherwise.
     */
    @SuppressWarnings("rawtypes")
    protected boolean isActiveCommitteeMember(ProtocolReviewableBase minute, String principalId) {
        String committeeId = "";
        String scheduleId = "";
        CommitteeScheduleBase committeeSchedule = minute.getCommitteeSchedule();
        if (committeeSchedule != null) {
            committeeId = minute.getCommitteeSchedule().getParentCommittee().getCommitteeId();
            scheduleId = minute.getCommitteeSchedule().getScheduleId();
        }
        return isActiveCommitteeMember(committeeId, scheduleId, principalId);
    }

    @SuppressWarnings("unchecked")
    protected boolean isActiveCommitteeMember(String committeeId, String scheduleId, String principalId) {
        boolean result = false;
        List<CommitteeMembershipBase> committeeMembers = committeeService.getAvailableMembers(committeeId,
                scheduleId);
        if (CollectionUtils.isNotEmpty(committeeMembers)) {
            for (CommitteeMembershipBase member : committeeMembers) {
                if (StringUtils.equals(principalId, member.getPersonId())) {
                    result = true;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * 
     * This method determines if the current user is an active committee member using the commitee and schedule ids
     * obtained from the submission parameter
     * 
     * @param submission
     * @param principalId
     * @return true if and active committee member, false otherwise.
     */
    private boolean isActiveCommitteeMember(ProtocolSubmissionBase submission, String principalId) {
        String committeeId = submission.getCommitteeId();
        String scheduleId = submission.getScheduleId();
        return isActiveCommitteeMember(committeeId, scheduleId, principalId);
    }

    protected abstract Class<? extends ProtocolOnlineReviewBase> getProtocolOnlineReviewClassHook();

    public void deleteReviewAttachment(List<PRA> reviewAttachments, int index, List<PRA> deletedReviewAttachments) {
        if (index >= 0 && index < reviewAttachments.size()) {
            PRA reviewAttachment = reviewAttachments.get(index);
            if (reviewAttachment.getReviewerAttachmentId() != null) {
                deletedReviewAttachments.add(reviewAttachment);
            }
            reviewAttachments.remove(index);
        }
    }

    public abstract void saveReviewAttachments(List<PRA> reviewAttachments, List<PRA> deletedReviewAttachments);

    public void addReviewAttachment(PRA newReviewAttachment, List<PRA> reviewAttachments, ProtocolBase protocol) {
        ProtocolSubmissionBase protocolSubmission = getSubmission(protocol);
        newReviewAttachment.setAttachmentId(getNextAttachmentId(protocol));
        newReviewAttachment.setProtocolIdFk(protocol.getProtocolId());
        newReviewAttachment.setProtocol(protocol);
        newReviewAttachment.setSubmissionIdFk(protocolSubmission.getSubmissionId());
        newReviewAttachment.setCreateUser(GlobalVariables.getUserSession().getPrincipalName());
        newReviewAttachment.setCreateTimestamp(dateTimeService.getCurrentTimestamp());
        newReviewAttachment.setUpdateUser(GlobalVariables.getUserSession().getPrincipalName());
        newReviewAttachment.setPersonId(GlobalVariables.getUserSession().getPrincipalId());
        newReviewAttachment.setPrivateFlag(!newReviewAttachment.isProtocolPersonCanView());
        // TO show update timestamp after 'add'
        newReviewAttachment.setUpdateTimestamp(dateTimeService.getCurrentTimestamp());
        final AttachmentFile newFile = AttachmentFile.createFromFormFile(newReviewAttachment.getNewFile());
        newReviewAttachment.setFile(newFile);
        // set to null, so the subsequent post will not creating new file again
        newReviewAttachment.setNewFile(null);

        reviewAttachments.add(newReviewAttachment);
    }

    /*
     * get next attachmentId. it seems coeus is just increasing by 1, no matter what protocol is. but attachment_id is only
     * number(3). so, need further investigation.
     */
    private int getNextAttachmentId(ProtocolBase protocol) {
        Map fieldValues = new HashMap();
        fieldValues.put("protocolIdFk", protocol.getProtocolId());
        List<PRA> reviewAttachments = (List<PRA>) businessObjectService
                .findMatchingOrderBy(getProtocolReviewAttachmentClassHook(), fieldValues, "attachmentId", false);
        if (CollectionUtils.isEmpty(reviewAttachments)) {
            return 1;
        } else {
            return reviewAttachments.get(0).getAttachmentId() + 1;
        }

    }

    protected abstract Class<PRA> getProtocolReviewAttachmentClassHook();

    @Override
    public void deleteAllReviewAttachments(List<PRA> reviewAttachments, List<PRA> deletedReviewAttachments) {
        for (PRA reviewerAttachment : reviewAttachments) {
            if (reviewerAttachment.getReviewerAttachmentId() != null) {
                deletedReviewAttachments.add(reviewerAttachment);
            }
        }
        reviewAttachments.clear();

    }

    public ProtocolFinderDao getProtocolFinderDao() {
        return protocolFinderDao;
    }

}