001/**
002 * Copyright 2005-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kim.web.struts.action;
017
018import java.sql.Timestamp;
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Calendar;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import javax.servlet.http.HttpServletRequest;
027import javax.servlet.http.HttpServletResponse;
028
029import org.apache.commons.lang.StringUtils;
030import org.apache.struts.action.ActionForm;
031import org.apache.struts.action.ActionForward;
032import org.apache.struts.action.ActionMapping;
033import org.kuali.rice.core.api.delegation.DelegationType;
034import org.kuali.rice.core.api.membership.MemberType;
035import org.kuali.rice.core.api.util.RiceConstants;
036import org.kuali.rice.core.api.util.RiceKeyConstants;
037import org.kuali.rice.kew.api.exception.WorkflowException;
038import org.kuali.rice.kim.api.KimConstants;
039import org.kuali.rice.kim.api.group.Group;
040import org.kuali.rice.kim.api.identity.Person;
041import org.kuali.rice.kim.api.identity.principal.Principal;
042import org.kuali.rice.kim.api.role.Role;
043import org.kuali.rice.kim.api.services.KimApiServiceLocator;
044import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember;
045import org.kuali.rice.kim.bo.ui.KimDocumentRolePermission;
046import org.kuali.rice.kim.bo.ui.KimDocumentRoleQualifier;
047import org.kuali.rice.kim.bo.ui.KimDocumentRoleResponsibility;
048import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMember;
049import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMemberQualifier;
050import org.kuali.rice.kim.document.IdentityManagementRoleDocument;
051import org.kuali.rice.kim.impl.responsibility.AddResponsibilityEvent;
052import org.kuali.rice.kim.impl.responsibility.ResponsibilityBo;
053import org.kuali.rice.kim.impl.type.KimTypeLookupableHelperServiceImpl;
054import org.kuali.rice.kim.rule.event.ui.AddDelegationMemberEvent;
055import org.kuali.rice.kim.rule.event.ui.AddMemberEvent;
056import org.kuali.rice.kim.rule.event.ui.AddPermissionEvent;
057import org.kuali.rice.kim.web.struts.form.IdentityManagementRoleDocumentForm;
058import org.kuali.rice.kns.question.ConfirmationQuestion;
059import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
060import org.kuali.rice.kns.web.struts.form.KualiTableRenderFormMetadata;
061import org.kuali.rice.krad.data.KradDataServiceLocator;
062import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
063import org.kuali.rice.krad.util.GlobalVariables;
064import org.kuali.rice.krad.util.KRADConstants;
065
066/**
067 * @author Kuali Rice Team (rice.collab@kuali.org)
068 */
069public class IdentityManagementRoleDocumentAction extends IdentityManagementDocumentActionBase {
070
071    public static final String CHANGE_DEL_ROLE_MEMBER_METHOD_TO_CALL = "changeDelegationRoleMember";
072    public static final String SWITCH_TO_ROLE_MEMBER_METHOD_TO_CALL = "jumpToRoleMember";
073    public static final String REMOVE_AFFECTED_DELEGATES_QUESTION_ID = "RemoveAffectedDelegates";
074
075    protected List<String> methodToCallToUncheckedList = new ArrayList<String>();
076
077    /**
078     * This method doesn't actually sort the column - it's just that we need a sort method in
079     * order to exploit the existing methodToCall logic. The sorting is handled in the execute
080     * method below, and delegated to the KualiTableRenderFormMetadata object.
081     *
082     * @param mapping
083     * @param form
084     * @param request
085     * @param response
086     * @return
087     * @throws Exception
088     */
089    {
090        methodToCallToUncheckedList.add(CHANGE_DEL_ROLE_MEMBER_METHOD_TO_CALL);
091        methodToCallToUncheckedList.add(CHANGE_MEMBER_TYPE_CODE_METHOD_TO_CALL);
092        methodToCallToUncheckedList.add(CHANGE_NAMESPACE_METHOD_TO_CALL);
093        methodToCallToUncheckedList.add(SWITCH_TO_ROLE_MEMBER_METHOD_TO_CALL);
094    }
095
096    /**
097     * This constructs a ...
098     */
099    public IdentityManagementRoleDocumentAction() {
100        super();
101        for (String methodToCallToUncheck : methodToCallToUncheckedList) {
102            addMethodToCallToUncheckedList(methodToCallToUncheck);
103        }
104    }
105
106    public ActionForward sort(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
107        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
108        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
109        memberTableMetadata.setSwitchToPageNumber(0);
110        return mapping.findForward(RiceConstants.MAPPING_BASIC);
111    }
112
113    @Override
114    public ActionForward execute(ActionMapping mapping, ActionForm form,
115            HttpServletRequest request, HttpServletResponse response) throws Exception {
116        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
117        if (roleDocumentForm.getRoleId() == null) {
118            String roleId = request.getParameter(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID);
119            roleDocumentForm.setRoleId(roleId);
120        }
121        String kimTypeId = request.getParameter(KimConstants.PrimaryKeyConstants.KIM_TYPE_ID);
122        setKimType(kimTypeId, roleDocumentForm);
123
124        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
125        if (roleDocumentForm.getRoleDocument()!=null && roleDocumentForm.getMemberRows() != null) {
126            memberTableMetadata.jumpToPage(memberTableMetadata.getViewedPageNumber(), roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
127            // KULRICE-3972: need to be able to sort by column header like on lookups when editing large roles and groups
128            memberTableMetadata.sort(roleDocumentForm.getMemberRows(), roleDocumentForm.getRecordsPerPage());
129        }
130
131        // KULRICE-4762: active delegates of "inactivated" role members cause validation problems
132        ActionForward forward = promptForAffectedDelegates(mapping, form, request, response,
133                roleDocumentForm);
134        // if we need to prompt the user due to affected delegates, do so:
135        if (forward != null) { return forward; }
136
137        forward = super.execute(mapping, roleDocumentForm, request, response);
138
139        roleDocumentForm.setCanAssignRole(validAssignRole(roleDocumentForm.getRoleDocument()));
140        if (KimTypeLookupableHelperServiceImpl.hasDerivedRoleTypeService(roleDocumentForm.getRoleDocument().getKimType())) {
141            roleDocumentForm.setCanModifyAssignees(false);
142        }
143        GlobalVariables.getUserSession().addObject(KimConstants.KimUIConstants.KIM_ROLE_DOCUMENT_SHORT_KEY, roleDocumentForm.getRoleDocument());
144        return forward;
145    }
146
147    /**
148     * This overridden method ...
149     *
150     * @see org.kuali.rice.krad.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.krad.web.struts.form.KualiDocumentFormBase)
151     */
152    @Override
153    protected void loadDocument(KualiDocumentFormBase form)
154            throws WorkflowException {
155        super.loadDocument(form);
156
157        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
158        setKimType(roleDocumentForm.getRoleDocument().getRoleTypeId(), roleDocumentForm);
159
160        getUiDocumentService().setDelegationMembersInDocument(roleDocumentForm.getRoleDocument());
161        getUiDocumentService().setMembersInDocument(roleDocumentForm.getRoleDocument());
162
163        roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
164        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
165
166        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
167        if (roleDocumentForm.getMemberRows() != null) {
168            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
169        }
170    }
171
172    /**
173     * This overridden method ...
174     *
175     * @see org.kuali.rice.krad.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.krad.web.struts.form.KualiDocumentFormBase)
176     */
177    @Override
178    protected void createDocument(KualiDocumentFormBase form)
179            throws WorkflowException {
180        super.createDocument(form);
181        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
182
183        if (roleDocumentForm.getRoleId() == null) {
184            roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
185            roleDocumentForm.getRoleDocument().initializeDocumentForNewRole();
186            roleDocumentForm.setRoleId(roleDocumentForm.getRoleDocument().getRoleId());
187            //roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(roleDocumentForm.getRoleDocument().getRoleTypeId()));
188        } else {
189            loadRoleIntoDocument(roleDocumentForm.getRoleId(), roleDocumentForm);
190        }
191
192        roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
193        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
194
195        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
196        if (roleDocumentForm.getMemberRows() != null) {
197            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
198        }
199    }
200
201    protected void setKimType(String kimTypeId, IdentityManagementRoleDocumentForm roleDocumentForm) {
202        if (StringUtils.isNotBlank(kimTypeId)) {
203            roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(kimTypeId));
204            if (roleDocumentForm.getRoleDocument() != null) {
205                roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
206            }
207        } else if (roleDocumentForm.getRoleDocument() != null && StringUtils.isNotBlank(roleDocumentForm.getRoleDocument().getRoleTypeId())) {
208            roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(
209                    roleDocumentForm.getRoleDocument().getRoleTypeId()));
210            roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
211        }
212    }
213
214    protected void loadRoleIntoDocument(String roleId, IdentityManagementRoleDocumentForm roleDocumentForm) {
215        Role role = KimApiServiceLocator.getRoleService().getRole(roleId);
216        roleDocumentForm.getRoleDocument().setMemberMetaDataTypeToSort(roleDocumentForm.getMemberTableMetadata().getColumnToSortIndex());
217        getUiDocumentService().loadRoleDoc(roleDocumentForm.getRoleDocument(), role);
218    }
219
220    /**
221     * @see org.kuali.rice.kim.web.struts.action.IdentityManagementDocumentActionBase#getActionName()
222     */
223    @Override
224    public String getActionName() {
225        return KimConstants.KimUIConstants.KIM_ROLE_DOCUMENT_ACTION;
226    }
227
228    protected boolean validAssignRole(IdentityManagementRoleDocument document) {
229        boolean rulePassed = true;
230        if (StringUtils.isNotEmpty(document.getRoleNamespace())) {
231            Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
232            additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, document.getRoleNamespace());
233            additionalPermissionDetails.put(KimConstants.AttributeConstants.ROLE_NAME, document.getRoleName());
234            if (!getDocumentHelperService().getDocumentAuthorizer(document).isAuthorizedByTemplate(
235                    document,
236                    KimConstants.NAMESPACE_CODE,
237                    KimConstants.PermissionTemplateNames.ASSIGN_ROLE,
238                    GlobalVariables.getUserSession().getPrincipalId(),
239                    additionalPermissionDetails, null)) {
240                rulePassed = false;
241            }
242        }
243        return rulePassed;
244    }
245
246    public ActionForward changeMemberTypeCode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
247        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
248        roleDocumentForm.getMember().setMemberId("");
249        return refresh(mapping, roleDocumentForm, request, response);
250    }
251
252    public ActionForward changeDelegationMemberTypeCode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
253        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
254        KimDocumentRoleMember roleMember = roleDocumentForm.getRoleDocument().getMember(roleDocumentForm.getDelegationMember().getRoleMemberId());
255        if (roleMember != null) {
256            RoleDocumentDelegationMemberQualifier delegationMemberQualifier;
257            for (KimDocumentRoleQualifier roleQualifier : roleMember.getQualifiers()) {
258                delegationMemberQualifier = roleDocumentForm.getDelegationMember().getQualifier(roleQualifier.getKimAttrDefnId());
259                delegationMemberQualifier.setAttrVal(roleQualifier.getAttrVal());
260            }
261        }
262        return refresh(mapping, roleDocumentForm, request, response);
263    }
264
265    public ActionForward addResponsibility(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
266        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
267        KimDocumentRoleResponsibility newResponsibility = roleDocumentForm.getResponsibility();
268        if (newResponsibility != null && StringUtils.isNotBlank(newResponsibility.getResponsibilityId())) {
269            ResponsibilityBo responsibilityImpl = KradDataServiceLocator.getDataObjectService().find(ResponsibilityBo.class, newResponsibility.getResponsibilityId());
270            newResponsibility.setKimResponsibility(responsibilityImpl);
271        }
272
273        if (KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddResponsibilityEvent("", roleDocumentForm.getRoleDocument(), newResponsibility))) {
274            if (newResponsibility != null) {
275                newResponsibility.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
276            }
277            roleDocumentForm.getRoleDocument().addResponsibility(newResponsibility);
278            roleDocumentForm.setResponsibility(new KimDocumentRoleResponsibility());
279            roleDocumentForm.getRoleDocument().updateMembers(newResponsibility);
280        }
281        return mapping.findForward(RiceConstants.MAPPING_BASIC);
282    }
283
284    public ActionForward deleteResponsibility(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
285        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
286        roleDocumentForm.getRoleDocument().getResponsibilities().remove(getLineToDelete(request));
287        roleDocumentForm.getRoleDocument().updateMembers(roleDocumentForm);
288        return mapping.findForward(RiceConstants.MAPPING_BASIC);
289    }
290
291    public ActionForward addPermission(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
292        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
293        KimDocumentRolePermission newPermission = roleDocumentForm.getPermission();
294        if (KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddPermissionEvent("", roleDocumentForm.getRoleDocument(), newPermission))) {
295            newPermission.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
296            newPermission.setRoleId(roleDocumentForm.getRoleDocument().getRoleId());
297            roleDocumentForm.getRoleDocument().getPermissions().add(newPermission);
298            roleDocumentForm.setPermission(new KimDocumentRolePermission());
299        }
300        return mapping.findForward(RiceConstants.MAPPING_BASIC);
301    }
302
303    public ActionForward addMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
304        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
305        KimDocumentRoleMember newMember = roleDocumentForm.getMember();
306
307        //See if possible to add with just Group Details filled in (not returned from lookup)
308        if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode())
309                && StringUtils.isEmpty(newMember.getMemberId())
310                && !newMember.isMemberNameNull()
311                && !newMember.isMemberNameSpaceCodeNull() ) {
312            Group tempGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
313                    newMember.getMemberNamespaceCode(), newMember.getMemberName());
314            if (tempGroup != null) {
315                newMember.setMemberId(tempGroup.getId());
316            }
317        }
318
319        //See if possible to grab details for Principal
320        if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())
321                && StringUtils.isEmpty(newMember.getMemberId())
322                && StringUtils.isNotEmpty(newMember.getMemberName())) {
323            Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(newMember.getMemberName());
324            if (principal != null) {
325                newMember.setMemberId(principal.getPrincipalId());
326                String fullName = checkMemberFullName(principal.getPrincipalId());
327                if (fullName != null) {
328                    newMember.setMemberFullName(fullName);
329                }
330            }
331        } else if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())
332                && StringUtils.isNotEmpty(newMember.getMemberId())
333                && StringUtils.isNotEmpty(newMember.getMemberName())) {
334            String fullName = checkMemberFullName(newMember.getMemberId());
335            if (fullName != null) {
336                newMember.setMemberFullName(fullName);
337            }
338        }
339
340        if (checkKimDocumentRoleMember(newMember) &&
341                KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddMemberEvent("", roleDocumentForm.getRoleDocument(), newMember))) {
342            newMember.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
343            roleDocumentForm.getRoleDocument().addMember(newMember);
344            roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
345        }
346        return mapping.findForward(RiceConstants.MAPPING_BASIC);
347    }
348
349    protected String checkMemberFullName(String principalId) {
350        Principal principal = getIdentityService().getPrincipal(principalId);
351        if (principal != null) {
352            Person psn = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principal.getPrincipalName());
353            if (psn != null) {
354                return psn.getFirstName() + " " + psn.getLastName();
355            }
356        }
357        return null;
358    }
359
360    protected boolean checkKimDocumentRoleMember(KimDocumentRoleMember newMember) {
361        boolean memberExists = false;
362        String memberName = null;
363        String memberNamespace = null;
364
365        if (StringUtils.isBlank(newMember.getMemberId())) {
366            GlobalVariables.getMessageMap().putError("document.member.memberId", RiceKeyConstants.ERROR_EMPTY_ENTRY,
367                    new String[]{"Member ID"});
368            return false;
369        }
370
371        if (MemberType.PRINCIPAL.getCode().equals(newMember.getMemberTypeCode())) {
372            Principal pi = this.getIdentityService().getPrincipal(newMember.getMemberId());
373            if (pi != null) {
374                memberExists = true;
375                memberName = pi.getPrincipalName();
376                memberNamespace = "";
377            }
378        } else if (MemberType.GROUP.getCode().equals(newMember.getMemberTypeCode())) {
379            Group gi = KimApiServiceLocator.getGroupService().getGroup(newMember.getMemberId());
380            if (gi != null) {
381                memberExists = true;
382                memberName = gi.getName();
383                memberNamespace = gi.getNamespaceCode();
384            }
385        } else if (MemberType.ROLE.getCode().equals(newMember.getMemberTypeCode())) {
386            Role ri = KimApiServiceLocator.getRoleService().getRole(newMember.getMemberId());
387            if (!validateRole(newMember.getMemberId(), ri, "document.member.memberId", "Role")) {
388                return false;
389            } else {
390                memberExists = true;
391                memberName = ri.getName();
392                memberNamespace = ri.getNamespaceCode();
393            }
394        }
395
396        if (!memberExists) {
397            GlobalVariables.getMessageMap().putError("document.member.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
398                    new String[]{newMember.getMemberId()});
399            return false;
400        }
401        newMember.setMemberName(memberName);
402        newMember.setMemberNamespaceCode(memberNamespace);
403        return true;
404    }
405
406    public ActionForward deleteMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
407        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
408        KimDocumentRoleMember inactivatedRoleMember = roleDocumentForm.getRoleDocument().getModifiedMembers().get(getLineToDelete(request));
409
410        // KULRICE-4762: active delegates of "inactivated" role members cause validation problems
411        ActionForward forward = promptForAffectedDelegates(mapping, form, request, response,
412                roleDocumentForm, /* we haven't actually inactivated them yet, so specify them here */ inactivatedRoleMember);
413        // if we need to prompt the user due to affected delegates, do so:
414        if (forward != null) {
415            return forward;
416        }
417
418        Calendar cal = Calendar.getInstance();
419        inactivatedRoleMember.setActiveToDate(new Timestamp(cal.getTimeInMillis()));
420
421        roleDocumentForm.getRoleDocument().getModifiedMembers().set(getLineToDelete(request), inactivatedRoleMember);
422        return mapping.findForward(RiceConstants.MAPPING_BASIC);
423    }
424
425    public ActionForward editMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
426        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
427        KimDocumentRoleMember roleMemberToEdit = roleDocumentForm.getRoleDocument().getMembers().get(getLineToEdit(request));
428        KimDocumentRoleMember copiedMember = KradDataServiceLocator.getDataObjectService().copyInstance(roleMemberToEdit);
429        roleDocumentForm.getRoleDocument().getModifiedMembers().add(copiedMember);
430        roleDocumentForm.getRoleDocument().getMembers().remove(roleMemberToEdit);
431        return mapping.findForward(RiceConstants.MAPPING_BASIC);
432    }
433
434    public ActionForward editSearchResultsMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
435        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
436        KimDocumentRoleMember roleMemberToEdit = roleDocumentForm.getRoleDocument().getSearchResultMembers().get(getLineToEdit(request));
437        KimDocumentRoleMember copiedMember = KradDataServiceLocator.getDataObjectService().copyInstance(roleMemberToEdit);
438        roleDocumentForm.getRoleDocument().getModifiedMembers().add(copiedMember);
439        roleDocumentForm.getRoleDocument().getSearchResultMembers().remove(roleMemberToEdit);
440        roleDocumentForm.getRoleDocument().getMembers().remove(roleMemberToEdit);
441        return mapping.findForward(RiceConstants.MAPPING_BASIC);
442    }
443
444    public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
445        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
446        String memberSearchValue = roleDocumentForm.getMemberSearchValue();
447        if (memberSearchValue != null && !memberSearchValue.isEmpty()) {
448            memberSearchValue = memberSearchValue.replaceAll("[%*]","");
449            getUiDocumentService().loadRoleMembersBasedOnSearch(roleDocumentForm.getRoleDocument(), memberSearchValue);
450        } else {
451            clear(mapping, form, request, response);
452        }
453        return mapping.findForward(RiceConstants.MAPPING_BASIC);
454    }
455
456    public ActionForward clear(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
457        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
458        roleDocumentForm.setMemberSearchValue("");
459        getUiDocumentService().clearRestrictedRoleMembersSearchResults(roleDocumentForm.getRoleDocument());
460
461        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
462        if (roleDocumentForm.getMemberRows() != null) {
463            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
464        }
465        return mapping.findForward(RiceConstants.MAPPING_BASIC);
466    }
467
468    public ActionForward deletePermission(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
469        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
470        roleDocumentForm.getRoleDocument().getPermissions().remove(getLineToDelete(request));
471        return mapping.findForward(RiceConstants.MAPPING_BASIC);
472    }
473
474    protected boolean checkDelegationMember(RoleDocumentDelegationMember newMember) {
475        if (StringUtils.isBlank(newMember.getMemberTypeCode()) || StringUtils.isBlank(newMember.getMemberId())) {
476            GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_EMPTY_ENTRY,
477                    new String[]{"Member Type Code and Member ID"});
478            return false;
479        }
480        if (MemberType.PRINCIPAL.getCode().equals(newMember.getMemberTypeCode())) {
481            Principal principalInfo = getIdentityService().getPrincipal(newMember.getMemberId());
482            if (principalInfo == null) {
483                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
484                        new String[]{newMember.getMemberId()});
485                return false;
486            } else {
487                newMember.setMemberName(principalInfo.getPrincipalName());
488            }
489        } else if (MemberType.GROUP.getCode().equals(newMember.getMemberTypeCode())) {
490            Group groupInfo = null;
491            groupInfo = getGroupService().getGroup(newMember.getMemberId());
492            if (groupInfo == null) {
493                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
494                        new String[]{newMember.getMemberId()});
495                return false;
496            } else {
497                newMember.setMemberName(groupInfo.getName());
498                newMember.setMemberNamespaceCode(groupInfo.getNamespaceCode());
499            }
500        } else if (MemberType.ROLE.getCode().equals(newMember.getMemberTypeCode())) {
501            Role roleInfo = KimApiServiceLocator.getRoleService().getRole(newMember.getMemberId());
502            if (roleInfo == null) {
503                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
504                        new String[]{newMember.getMemberId()});
505                return false;
506            } else {
507                newMember.setMemberName(roleInfo.getName());
508                newMember.setMemberNamespaceCode(roleInfo.getNamespaceCode());
509            }
510        }
511        return true;
512    }
513
514    public ActionForward addDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
515        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
516        RoleDocumentDelegationMember newDelegationMember = roleDocumentForm.getDelegationMember();
517
518        //See if possible to add with just Group Details filled in (not returned from lookup)
519        if (StringUtils.isEmpty(newDelegationMember.getMemberId())
520                && StringUtils.isNotEmpty(newDelegationMember.getMemberName())
521                && StringUtils.isNotEmpty(newDelegationMember.getMemberNamespaceCode())
522                && StringUtils.equals(newDelegationMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode())) {
523            Group tempGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
524                    newDelegationMember.getMemberNamespaceCode(), newDelegationMember.getMemberName());
525            if (tempGroup != null) {
526                newDelegationMember.setMemberId(tempGroup.getId());
527            }
528        }
529
530        //See if possible to grab details for Principal
531        if (StringUtils.isEmpty(newDelegationMember.getMemberId())
532                && StringUtils.isNotEmpty(newDelegationMember.getMemberName())
533                && StringUtils.equals(newDelegationMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())) {
534            Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(newDelegationMember.getMemberName());
535            if (principal != null) {
536                newDelegationMember.setMemberId(principal.getPrincipalId());
537            }
538        }
539
540        if (checkDelegationMember(newDelegationMember) && KRADServiceLocatorWeb.getKualiRuleService().applyRules(
541                new AddDelegationMemberEvent("", roleDocumentForm.getRoleDocument(), newDelegationMember))) {
542            newDelegationMember.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
543            if (StringUtils.isEmpty(newDelegationMember.getDelegationTypeCode())) {
544               newDelegationMember.setDelegationTypeCode(DelegationType.SECONDARY.getCode());
545            }
546            roleDocumentForm.getRoleDocument().addDelegationMember(newDelegationMember);
547            roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
548        }
549        return mapping.findForward(RiceConstants.MAPPING_BASIC);
550    }
551
552    public ActionForward deleteDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
553        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
554        // Removing, not inactivating -- is this what we really want?
555        roleDocumentForm.getRoleDocument().getDelegationMembers().remove(getLineToDelete(request));
556        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
557        return mapping.findForward(RiceConstants.MAPPING_BASIC);
558    }
559
560    /**
561     * @see org.kuali.rice.kns.web.struts.action.KualiTableRenderAction#switchToPage(org.apache.struts.action.ActionMapping,
562     *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
563     */
564    public ActionForward jumpToRoleMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
565        IdentityManagementRoleDocumentForm idmForm = (IdentityManagementRoleDocumentForm) form;
566        String delegationRoleMemberId = getDelegationRoleMemberToJumpTo(request);
567        KualiTableRenderFormMetadata memberTableMetadata = idmForm.getMemberTableMetadata();
568        memberTableMetadata.jumpToPage(idmForm.getPageNumberOfRoleMemberId(delegationRoleMemberId),
569                idmForm.getMemberRows().size(), idmForm.getRecordsPerPage());
570        memberTableMetadata.setColumnToSortIndex(memberTableMetadata.getPreviouslySortedColumnIndex());
571        idmForm.setAnchor(delegationRoleMemberId);
572        return mapping.findForward(RiceConstants.MAPPING_BASIC);
573    }
574
575    protected String getDelegationRoleMemberToJumpTo(HttpServletRequest request) {
576        String delegationRoleMemberIdToJumpTo = "";
577        String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
578        if (StringUtils.isNotBlank(parameterName)) {
579            delegationRoleMemberIdToJumpTo = StringUtils.substringBetween(parameterName, ".dmrmi", ".");
580        }
581        return delegationRoleMemberIdToJumpTo;
582    }
583
584
585    /**
586     * Side-effecting method returns an ActionForward if needed for handling prompting of the user about automatically
587     * "inactivating" active delegates of inactive role members.  If the user has already responded "Yes", delegates are
588     * "inactivated" here, and a null forward is returned.  Otherwise, an appropriate forward is returned.
589     *
590     * @param roleMembersToConsiderInactive additional role members to consider inactive for the purposes of this computation
591     */
592    private ActionForward promptForAffectedDelegates(ActionMapping mapping,
593            ActionForm form, HttpServletRequest request,
594            HttpServletResponse response,
595            IdentityManagementRoleDocumentForm roleDocumentForm, KimDocumentRoleMember... roleMembersToConsiderInactive)
596            throws Exception {
597        // KULRICE-4762: Role: Removed an Assignee who has delegations associated with him and now the Role cannot be updated
598        // To solve this issue, prompt for confirmation if there are active delegates for the role member being "inactivated",
599        // and upon confirmation, "inactivate" the delegates too.
600        List<RoleDocumentDelegationMember> activeDelegatesOfInactiveRoleMembers =
601                getActiveDelegatesOfInactiveRoleMembers(roleDocumentForm, roleMembersToConsiderInactive);
602        ActionForward forward = getAffectedDelegatesQuestionActionForward(activeDelegatesOfInactiveRoleMembers, mapping, form, request,
603                response, roleDocumentForm);
604        // if the question logic gave us a forward, do it
605        if (forward != null) {
606            return forward;
607        }
608        // otherwise, inactivate affected delegates
609        if (activeDelegatesOfInactiveRoleMembers.size() > 0) {
610            Calendar cal = Calendar.getInstance();
611            // deactivate (inactivate?) delegates
612            for (RoleDocumentDelegationMember delegateToDeactivate : activeDelegatesOfInactiveRoleMembers) {
613                delegateToDeactivate.setActiveToDate(new Timestamp(cal.getTimeInMillis()));
614            }
615        }
616        return null;
617    }
618
619    /**
620     * <p>If there are active delegates of an "inactivated" role member, return an ActionForward to prompt the user
621     * letting them know that the delegates will be "inactivated" too if they proceed.
622     * <p>Also, if the user has already responded to the question and the response was (1) "Yes", then return null, signifying
623     * that we can go ahead and take the needed action to "inactivate" the delegates; or (2) "No", then return a basic forward that
624     * will cancel further action.
625     */
626    private ActionForward getAffectedDelegatesQuestionActionForward(List<RoleDocumentDelegationMember> activeDelegatesOfInactiveRoleMembers,
627            ActionMapping mapping, ActionForm form, HttpServletRequest request,
628            HttpServletResponse response,
629            IdentityManagementRoleDocumentForm roleDocumentForm)
630            throws Exception {
631
632        if (activeDelegatesOfInactiveRoleMembers.size() > 0) {
633            Object question = getQuestion(request);
634            // logic for delegates question
635            if (question == null || !REMOVE_AFFECTED_DELEGATES_QUESTION_ID.equals(question)) {
636                return performQuestionWithoutInput(mapping, form, request, response, REMOVE_AFFECTED_DELEGATES_QUESTION_ID,
637                        getKualiConfigurationService().getPropertyValueAsString(
638                                RiceKeyConstants.QUESTION_ACTIVE_DELEGATES_FOR_INACTIVE_MEMBERS),
639                        KRADConstants.CONFIRMATION_QUESTION, roleDocumentForm.getMethodToCall(), StringUtils.EMPTY);
640            }
641            Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON);
642            if ((REMOVE_AFFECTED_DELEGATES_QUESTION_ID.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {
643                // the question was answered in the affirmative.
644                // fall through, no special mapping to return
645            } else {
646                // NO was clicked ... what to do?  Return basic mapping without "inactivating" anything
647                return mapping.findForward(RiceConstants.MAPPING_BASIC);
648            }
649        }
650
651        return null;
652    }
653
654    /**
655     * This method returns a list of all active delegates for role members that are inactive
656     *
657     * @param roleDocumentForm              form bean
658     * @param roleMembersToConsiderInactive additional role members to consider inactive for the purposes of this computation
659     * @return the active delegates of inactive role members
660     */
661    private List<RoleDocumentDelegationMember> getActiveDelegatesOfInactiveRoleMembers(
662            IdentityManagementRoleDocumentForm roleDocumentForm, KimDocumentRoleMember... roleMembersToConsiderInactive) {
663        List<KimDocumentRoleMember> roleMembers = roleDocumentForm.getMemberRows();
664        List<KimDocumentRoleMember> inactiveRoleMembers = new ArrayList<KimDocumentRoleMember>();
665        List<RoleDocumentDelegationMember> activeDelegatesOfInactivatedRoleMembers = new ArrayList<RoleDocumentDelegationMember>();
666
667        inactiveRoleMembers.addAll(Arrays.asList(roleMembersToConsiderInactive));
668
669        if (roleMembers != null) {
670            for (KimDocumentRoleMember roleMember : roleMembers) {
671                if (roleMember != null) {
672                    if (!roleMember.isActive()) {
673                        inactiveRoleMembers.add(roleMember);
674                    }
675                }
676            }
677        }
678
679        for (KimDocumentRoleMember inactiveRoleMember : inactiveRoleMembers) {
680            // check if there are delegates for the member being removed
681            List<RoleDocumentDelegationMember> delegationMembers = roleDocumentForm.getRoleDocument().getDelegationMembers();
682            if (delegationMembers != null) {
683                for (RoleDocumentDelegationMember delegationMember : delegationMembers) {
684                    if (delegationMember != null && delegationMember.isActive()) {
685                        // if the roleMember for this delegation is the same as the inactivatedRoleMember
686                        if (delegationMember.getRoleMemberId().equals(inactiveRoleMember.getRoleMemberId())) {
687                            activeDelegatesOfInactivatedRoleMembers.add(delegationMember);
688                        }
689                    }
690                }
691            }
692        }
693        return activeDelegatesOfInactivatedRoleMembers;
694    }
695
696    /**
697     * This method overrides validateRole() from IdentityManagementDocumentActionBase.
698     * The difference with this method is that it allows derived roles.
699     * The base implementation returns false if the role is a derived role.
700     *
701     */
702    @Override
703    protected boolean validateRole(String roleId, Role role, String propertyName, String message) {
704        if (role == null) {
705            GlobalVariables.getMessageMap().putError(propertyName, RiceKeyConstants.ERROR_INVALID_ROLE, roleId);
706            return false;
707        }
708        return true;
709    }
710
711
712}