001    /**
002     * Copyright 2005-2011 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     */
016    package org.kuali.rice.kim.impl.role;
017    
018    import org.apache.commons.collections.CollectionUtils;
019    import org.apache.commons.lang.StringUtils;
020    import org.apache.log4j.Logger;
021    import org.joda.time.DateTime;
022    import org.kuali.rice.core.api.criteria.GenericQueryResults;
023    import org.kuali.rice.core.api.criteria.QueryByCriteria;
024    import org.kuali.rice.core.api.delegation.DelegationType;
025    import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
026    import org.kuali.rice.core.api.exception.RiceIllegalStateException;
027    import org.kuali.rice.core.api.membership.MemberType;
028    import org.kuali.rice.core.api.mo.ModelObjectUtils;
029    import org.kuali.rice.kim.api.KimConstants;
030    import org.kuali.rice.kim.api.common.delegate.DelegateMember;
031    import org.kuali.rice.kim.api.common.delegate.DelegateType;
032    import org.kuali.rice.kim.api.role.DelegateMemberQueryResults;
033    import org.kuali.rice.kim.api.role.Role;
034    import org.kuali.rice.kim.api.role.RoleMember;
035    import org.kuali.rice.kim.api.role.RoleMemberQueryResults;
036    import org.kuali.rice.kim.api.role.RoleMembership;
037    import org.kuali.rice.kim.api.role.RoleMembershipQueryResults;
038    import org.kuali.rice.kim.api.role.RoleQueryResults;
039    import org.kuali.rice.kim.api.role.RoleResponsibility;
040    import org.kuali.rice.kim.api.role.RoleResponsibilityAction;
041    import org.kuali.rice.kim.api.role.RoleService;
042    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
043    import org.kuali.rice.kim.api.type.KimType;
044    import org.kuali.rice.kim.framework.common.delegate.DelegationTypeService;
045    import org.kuali.rice.kim.framework.role.RoleTypeService;
046    import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator;
047    import org.kuali.rice.kim.framework.type.KimTypeService;
048    import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo;
049    import org.kuali.rice.kim.impl.common.delegate.DelegateMemberAttributeDataBo;
050    import org.kuali.rice.kim.impl.common.delegate.DelegateMemberBo;
051    import org.kuali.rice.kim.impl.common.delegate.DelegateTypeBo;
052    import org.kuali.rice.kim.impl.services.KimImplServiceLocator;
053    import org.kuali.rice.krad.service.KRADServiceLocator;
054    import org.springframework.util.LinkedMultiValueMap;
055    import org.springframework.util.MultiValueMap;
056    
057    import javax.jws.WebParam;
058    import java.sql.Timestamp;
059    import java.util.ArrayList;
060    import java.util.Collection;
061    import java.util.Collections;
062    import java.util.Date;
063    import java.util.HashMap;
064    import java.util.HashSet;
065    import java.util.List;
066    import java.util.Map;
067    import java.util.Set;
068    
069    import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
070    
071    public class RoleServiceImpl extends RoleServiceBase implements RoleService {
072        private static final Logger LOG = Logger.getLogger(RoleServiceImpl.class);
073    
074        private static final Map<String, RoleDaoAction> memberTypeToRoleDaoActionMap = populateMemberTypeToRoleDaoActionMap();
075    
076        private static Map<String, RoleDaoAction> populateMemberTypeToRoleDaoActionMap() {
077            Map<String, RoleDaoAction> map = new HashMap<String, RoleDaoAction>();
078            map.put(MemberType.GROUP.getCode(), RoleDaoAction.ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS);
079            map.put(MemberType.PRINCIPAL.getCode(), RoleDaoAction.ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS);
080            map.put(MemberType.ROLE.getCode(), RoleDaoAction.ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS);
081            return Collections.unmodifiableMap(map);
082        }
083    
084    
085        @Override
086        public Role createRole(final Role role) throws RiceIllegalArgumentException, RiceIllegalStateException {
087            incomingParamCheck(role, "role");
088    
089            if (StringUtils.isNotBlank(role.getId()) && getRole(role.getId()) != null) {
090                throw new RiceIllegalStateException("the role to create already exists: " + role);
091            }
092            RoleBo bo = RoleBo.from(role);
093            return RoleBo.to(getBusinessObjectService().save(bo));
094        }
095    
096        @Override
097        public Role updateRole(final Role role) throws RiceIllegalArgumentException, RiceIllegalStateException {
098            incomingParamCheck(role, "role");
099    
100            RoleBo originalRole = getRoleBo(role.getId());
101            if (StringUtils.isBlank(role.getId()) || originalRole == null) {
102                throw new RiceIllegalStateException("the role does not exist: " + role);
103            }
104    
105            RoleBo bo = RoleBo.from(role);
106    
107            RoleBo updatedRole = getBusinessObjectService().save(bo);
108            if (originalRole.isActive()
109                    && !updatedRole.isActive()) {
110                KimImplServiceLocator.getRoleInternalService().roleInactivated(updatedRole.getId());
111            }
112            return RoleBo.to(updatedRole);
113        }
114    
115        /**
116         * This method tests to see if assigning a roleBo to another roleBo will create a circular reference.
117         * The Role is checked to see if it is a member (direct or nested) of the roleBo to be assigned as a member.
118         *
119         * @param newMemberId
120         * @param roleBo
121         * @return true  - assignment is allowed, no circular reference will be created.
122         *         false - illegal assignment, it will create a circular membership
123         */
124        protected boolean checkForCircularRoleMembership(String newMemberId, RoleBo roleBo) {
125            // get all nested roleBo members that are of type roleBo
126            Set<String> newRoleMemberIds = getRoleTypeRoleMemberIds(newMemberId);
127            return !newRoleMemberIds.contains(roleBo.getId());
128        }
129    
130        protected RoleMember findRoleMember(String roleMemberId) {
131            final List<RoleMember> roleMembers = findRoleMembers(QueryByCriteria.Builder.fromPredicates(equal(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMemberId))).getResults();
132            if (roleMembers != null && !roleMembers.isEmpty()) {
133                return roleMembers.get(0);
134            }
135            return null;
136        }
137    
138        @Override
139        public RoleMemberQueryResults findRoleMembers(QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
140            incomingParamCheck(queryByCriteria, "queryByCriteria");
141    
142            GenericQueryResults<RoleMemberBo> results = getCriteriaLookupService().lookup(RoleMemberBo.class, queryByCriteria);
143    
144            RoleMemberQueryResults.Builder builder = RoleMemberQueryResults.Builder.create();
145            builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
146            builder.setTotalRowCount(results.getTotalRowCount());
147    
148            final List<RoleMember.Builder> ims = new ArrayList<RoleMember.Builder>();
149            for (RoleMemberBo bo : results.getResults()) {
150                ims.add(RoleMember.Builder.create(bo));
151            }
152    
153            builder.setResults(ims);
154            return builder.build();
155        }
156    
157        @Override
158        public Set<String> getRoleTypeRoleMemberIds(String roleId) throws RiceIllegalStateException  {
159            incomingParamCheck(roleId, "roleId");
160    
161            Set<String> results = new HashSet<String>();
162            getNestedRoleTypeMemberIds(roleId, results);
163            return Collections.unmodifiableSet(results);
164        }
165    
166        @Override
167        public List<String> getMemberParentRoleIds(String memberType, String memberId) throws RiceIllegalStateException  {
168            incomingParamCheck(memberType, "memberType");
169            incomingParamCheck(memberId, "memberId");
170    
171            List<RoleMemberBo> parentRoleMembers = getRoleDao().getRoleMembershipsForMemberId(memberType, memberId,
172                    Collections.<String, String>emptyMap());
173    
174            List<String> parentRoleIds = new ArrayList<String>(parentRoleMembers.size());
175            for (RoleMemberBo parentRoleMember : parentRoleMembers) {
176                parentRoleIds.add(parentRoleMember.getRoleId());
177            }
178    
179            return parentRoleIds;
180        }
181    
182        @Override
183        public List<RoleResponsibilityAction> getRoleMemberResponsibilityActions(String roleMemberId) throws RiceIllegalStateException  {
184            incomingParamCheck(roleMemberId, "roleMemberId");
185    
186            Map<String, String> criteria = new HashMap<String, String>(1);
187            criteria.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMemberId);
188    
189            List<RoleResponsibilityActionBo> responsibilityActionBoList = (List<RoleResponsibilityActionBo>)
190                    getBusinessObjectService().findMatching(RoleResponsibilityActionBo.class, criteria);
191    
192            List<RoleResponsibilityAction> roleResponsibilityActionsList = new ArrayList<RoleResponsibilityAction>();
193            for (RoleResponsibilityActionBo roleResponsibilityActionBo : responsibilityActionBoList) {
194                RoleResponsibilityAction roleResponsibility = RoleResponsibilityActionBo.to(roleResponsibilityActionBo);
195                roleResponsibilityActionsList.add(roleResponsibility);
196            }
197            return roleResponsibilityActionsList;
198        }
199    
200        @Override
201        public DelegateMemberQueryResults findDelegateMembers(QueryByCriteria queryByCriteria) throws RiceIllegalStateException  {
202            incomingParamCheck(queryByCriteria, "queryByCriteria");
203    
204            GenericQueryResults<DelegateMemberBo> results = getCriteriaLookupService().lookup(DelegateMemberBo.class, queryByCriteria);
205    
206            DelegateMemberQueryResults.Builder builder = DelegateMemberQueryResults.Builder.create();
207            builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
208            builder.setTotalRowCount(results.getTotalRowCount());
209    
210            final List<DelegateMember.Builder> ims = new ArrayList<DelegateMember.Builder>();
211            for (DelegateMemberBo bo : results.getResults()) {
212                ims.add(DelegateMember.Builder.create(bo));
213            }
214    
215            builder.setResults(ims);
216            return builder.build();
217        }
218    
219        @Override
220        public Role getRole(String roleId) throws RiceIllegalStateException  {
221            incomingParamCheck(roleId, "rpleId");
222    
223            RoleBo roleBo = getRoleBo(roleId);
224            if (roleBo == null) {
225                return null;
226            }
227            return RoleBo.to(roleBo);
228        }
229    
230        protected Map<String, RoleBo> getRoleBoMap(Collection<String> roleIds) {
231            Map<String, RoleBo> result;
232            // check for a non-null result in the cache, return it if found
233            if (roleIds.size() == 1) {
234                String roleId = roleIds.iterator().next();
235                RoleBo bo = getRoleBo(roleId);
236                result = bo.isActive() ? Collections.singletonMap(roleId, bo) :  Collections.<String, RoleBo>emptyMap();
237            } else {
238                result = new HashMap<String, RoleBo>(roleIds.size());
239                for (String roleId : roleIds) {
240                    RoleBo bo = getRoleBo(roleId);
241                    if (bo.isActive()) {
242                        result.put(roleId, bo);
243                    }
244                }
245            }
246            return result;
247        }
248    
249        @Override
250        public List<Role> getRoles(List<String> roleIds) throws RiceIllegalStateException  {
251            if (CollectionUtils.isEmpty(roleIds)) {
252                throw new RiceIllegalArgumentException("roleIds is null or empty");
253            }
254    
255            Collection<RoleBo> roleBos = getRoleBoMap(roleIds).values();
256            List<Role> roles = new ArrayList<Role>(roleBos.size());
257            for (RoleBo bo : roleBos) {
258                roles.add(RoleBo.to(bo));
259            }
260            return Collections.unmodifiableList(roles);
261        }
262    
263        @Override
264        public Role getRoleByNameAndNamespaceCode(String namespaceCode, String roleName) throws RiceIllegalStateException  {
265            incomingParamCheck(namespaceCode, "namespaceCode");
266            incomingParamCheck(roleName, "roleName");
267    
268            RoleBo roleBo = getRoleBoByName(namespaceCode, roleName);
269            if (roleBo != null) {
270                return RoleBo.to(roleBo);
271            }
272            return null;
273        }
274    
275        @Override
276        public String getRoleIdByNameAndNamespaceCode(String namespaceCode, String roleName) throws RiceIllegalStateException  {
277            incomingParamCheck(namespaceCode, "namespaceCode");
278            incomingParamCheck(roleName, "roleName");
279    
280            Role role = getRoleByNameAndNamespaceCode(namespaceCode, roleName);
281            if (role != null) {
282                return role.getId();
283            } else {
284                return null;
285            }
286        }
287    
288        @Override
289        public boolean isRoleActive(String roleId) throws RiceIllegalStateException  {
290            incomingParamCheck(roleId, "roleId");
291    
292            RoleBo roleBo = getRoleBo(roleId);
293            return roleBo != null && roleBo.isActive();
294        }
295    
296        @Override
297        public List<Map<String, String>> getRoleQualifersForPrincipalByRoleIds(String principalId, List<String> roleIds,
298                Map<String, String> qualification) throws RiceIllegalStateException  {
299            incomingParamCheck(principalId, "principalId");
300            incomingParamCheck(roleIds, "roleIds");
301            incomingParamCheck(qualification, "qualification");
302    
303            List<Map<String, String>> results = new ArrayList<Map<String, String>>();
304    
305            List<RoleMemberBo> roleMemberBoList = getStoredRoleMembersUsingExactMatchOnQualification(principalId, null,
306                    roleIds, qualification);
307    
308            Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
309            for (RoleMemberBo roleMemberBo : roleMemberBoList) {
310                // gather up the qualifier sets and the service they go with
311                if (MemberType.PRINCIPAL.equals(roleMemberBo.getMemberType())) {
312                    RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
313                    if (roleTypeService != null) {
314                        List<RoleMembership> las = roleIdToMembershipMap.get(roleMemberBo.getRoleId());
315                        if (las == null) {
316                            las = new ArrayList<RoleMembership>();
317                            roleIdToMembershipMap.put(roleMemberBo.getRoleId(), las);
318                        }
319                        RoleMembership mi = RoleMembership.Builder.create(
320                                roleMemberBo.getRoleId(),
321                                roleMemberBo.getRoleMemberId(),
322                                roleMemberBo.getMemberId(),
323                                roleMemberBo.getMemberType(),
324                                roleMemberBo.getAttributes()).build();
325    
326                        las.add(mi);
327                    } else {
328                        results.add(roleMemberBo.getAttributes());
329                    }
330                }
331            }
332            for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
333                RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
334                //it is possible that the the roleTypeService is coming from a remote application
335                // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
336                try {
337                    List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification, entry.getValue());
338                    for (RoleMembership rmi : matchingMembers) {
339                        results.add(rmi.getQualifier());
340                    }
341                } catch (Exception ex) {
342                    LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
343                }
344            }
345            return Collections.unmodifiableList(results);
346        }
347    
348        @Override
349        public List<Map<String, String>> getRoleQualifersForPrincipalByNamespaceAndRolename(String principalId,
350                String namespaceCode, String roleName, Map<String, String> qualification)
351                throws RiceIllegalStateException {
352            incomingParamCheck(principalId, "principalId");
353            incomingParamCheck(namespaceCode, "namespaceCode");
354            incomingParamCheck(roleName, "roleName");
355            incomingParamCheck(qualification, "qualification");
356    
357            String roleId = getRoleIdByNameAndNamespaceCode(namespaceCode, roleName);
358            if (roleId == null) {
359                return Collections.emptyList();
360            }
361            return getNestedRoleQualifiersForPrincipalByRoleIds(principalId, Collections.singletonList(roleId),
362                    qualification);
363        }
364    
365        @Override
366        public List<Map<String, String>> getNestedRoleQualifersForPrincipalByNamespaceAndRolename(String principalId,
367                String namespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
368            incomingParamCheck(principalId, "principalId");
369            incomingParamCheck(namespaceCode, "namespaceCode");
370            incomingParamCheck(roleName, "roleName");
371            incomingParamCheck(qualification, "qualification");
372    
373            String roleId = getRoleIdByNameAndNamespaceCode(namespaceCode, roleName);
374            if (roleId == null) {
375                return new ArrayList<Map<String, String>>(0);
376            }
377            return getNestedRoleQualifiersForPrincipalByRoleIds(principalId, Collections.singletonList(roleId),
378                    qualification);
379        }
380    
381        @Override
382        public List<Map<String, String>> getNestedRoleQualifiersForPrincipalByRoleIds(String principalId,
383                List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
384            incomingParamCheck(principalId, "principalId");
385            incomingParamCheck(roleIds, "roleIds");
386            incomingParamCheck(qualification, "qualification");
387    
388    
389            List<Map<String, String>> results = new ArrayList<Map<String, String>>();
390    
391            Map<String, RoleBo> roleBosById = getRoleBoMap(roleIds);
392    
393            // get the person's groups
394            List<String> groupIds = getGroupService().getGroupIdsByPrincipalId(principalId);
395            List<RoleMemberBo> roleMemberBos = getStoredRoleMembersUsingExactMatchOnQualification(principalId, groupIds, roleIds, qualification);
396    
397            Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
398            for (RoleMemberBo roleMemberBo : roleMemberBos) {
399                RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
400                // gather up the qualifier sets and the service they go with
401                if (MemberType.PRINCIPAL.equals(roleMemberBo.getMemberType())
402                        || MemberType.GROUP.equals(roleMemberBo.getMemberType())) {
403                    if (roleTypeService != null) {
404                        List<RoleMembership> las = roleIdToMembershipMap.get(roleMemberBo.getRoleId());
405                        if (las == null) {
406                            las = new ArrayList<RoleMembership>();
407                            roleIdToMembershipMap.put(roleMemberBo.getRoleId(), las);
408                        }
409                        RoleMembership mi = RoleMembership.Builder.create(
410                                roleMemberBo.getRoleId(),
411                                roleMemberBo.getRoleMemberId(),
412                                roleMemberBo.getMemberId(),
413                                roleMemberBo.getMemberType(),
414                                roleMemberBo.getAttributes()).build();
415    
416                        las.add(mi);
417                    } else {
418                        results.add(roleMemberBo.getAttributes());
419                    }
420                } else if (MemberType.ROLE.equals(roleMemberBo.getMemberType())) {
421                    // find out if the user has the role
422                    // need to convert qualification using this role's service
423                    Map<String, String> nestedQualification = qualification;
424                    if (roleTypeService != null) {
425                        RoleBo roleBo = roleBosById.get(roleMemberBo.getRoleId());
426                        // pulling from here as the nested roleBo is not necessarily (and likely is not)
427                        // in the roleBosById Map created earlier
428                        RoleBo nestedRole = getRoleBo(roleMemberBo.getMemberId());
429                        //it is possible that the the roleTypeService is coming from a remote application
430                        // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
431                        try {
432                            nestedQualification = roleTypeService.convertQualificationForMemberRoles(roleBo.getNamespaceCode(), roleBo.getName(), nestedRole.getNamespaceCode(), nestedRole.getName(), qualification);
433                        } catch (Exception ex) {
434                            LOG.warn("Not able to retrieve RoleTypeService from remote system for roleBo Id: " + roleBo.getId(), ex);
435                        }
436                    }
437                    List<String> nestedRoleId = new ArrayList<String>(1);
438                    nestedRoleId.add(roleMemberBo.getMemberId());
439                    // if the user has the given role, add the qualifier the *nested role* has with the
440                    // originally queries role
441                    if (principalHasRole(principalId, nestedRoleId, nestedQualification, false)) {
442                        results.add(roleMemberBo.getAttributes());
443                    }
444                }
445            }
446            for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
447                RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
448                //it is possible that the the roleTypeService is coming from a remote application
449                // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
450                try {
451                    List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification,
452                            entry.getValue());
453                    for (RoleMembership roleMembership : matchingMembers) {
454                        results.add(roleMembership.getQualifier());
455                    }
456                } catch (Exception ex) {
457                    LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
458                }
459            }
460            return Collections.unmodifiableList(results);
461        }
462    
463        @Override
464        public List<RoleMembership> getRoleMembers(List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
465            incomingParamCheck(roleIds, "roleIds");
466            incomingParamCheck(qualification, "qualification");
467    
468            Set<String> foundRoleTypeMembers = new HashSet<String>();
469            return getRoleMembers(roleIds, qualification, true, foundRoleTypeMembers);
470        }
471    
472        @Override
473        public Collection<String> getRoleMemberPrincipalIds(String namespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
474            incomingParamCheck(namespaceCode, "namespaceCode");
475            incomingParamCheck(roleName, "roleName");
476            incomingParamCheck(qualification, "qualification");
477    
478            Set<String> principalIds = new HashSet<String>();
479            Set<String> foundRoleTypeMembers = new HashSet<String>();
480            List<String> roleIds = Collections.singletonList(getRoleIdByNameAndNamespaceCode(namespaceCode, roleName));
481            for (RoleMembership roleMembership : getRoleMembers(roleIds, qualification, false, foundRoleTypeMembers)) {
482                if (MemberType.GROUP.equals(roleMembership.getMemberType())) {
483                    principalIds.addAll(getGroupService().getMemberPrincipalIds(roleMembership.getMemberId()));
484                } else {
485                    principalIds.add(roleMembership.getMemberId());
486                }
487            }
488            return Collections.unmodifiableSet(principalIds);
489        }
490    
491        @Override
492        public boolean principalHasRole(String principalId, List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
493            incomingParamCheck(principalId, "principalId");
494            incomingParamCheck(roleIds, "roleIds");
495            incomingParamCheck(qualification, "qualification");
496    
497            return principalHasRole(principalId, roleIds, qualification, true);
498        }
499    
500        @Override
501        public List<String> getPrincipalIdSubListWithRole(List<String> principalIds,
502                String roleNamespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
503            incomingParamCheck(principalIds, "principalIds");
504            incomingParamCheck(roleNamespaceCode, "roleNamespaceCode");
505            incomingParamCheck(roleName, "roleName");
506            incomingParamCheck(qualification, "qualification");
507    
508            List<String> subList = new ArrayList<String>();
509            RoleBo role = getRoleBoByName(roleNamespaceCode, roleName);
510            for (String principalId : principalIds) {
511                if (principalHasRole(principalId, Collections.singletonList(role.getId()), qualification)) {
512                    subList.add(principalId);
513                }
514            }
515            return Collections.unmodifiableList(subList);
516        }
517    
518        @Override
519        public RoleQueryResults findRoles(QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
520            incomingParamCheck(queryByCriteria, "queryByCriteria");
521    
522            GenericQueryResults<RoleBo> results = getCriteriaLookupService().lookup(RoleBo.class, queryByCriteria);
523    
524            RoleQueryResults.Builder builder = RoleQueryResults.Builder.create();
525            builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
526            builder.setTotalRowCount(results.getTotalRowCount());
527    
528            final List<Role.Builder> ims = new ArrayList<Role.Builder>();
529            for (RoleBo bo : results.getResults()) {
530                ims.add(Role.Builder.create(bo));
531            }
532    
533            builder.setResults(ims);
534            return builder.build();
535        }
536    
537        @Override
538        public List<RoleMembership> getFirstLevelRoleMembers(List<String> roleIds) throws RiceIllegalStateException {
539            incomingParamCheck(roleIds, "roleIds");
540            if (roleIds.isEmpty()) {
541                return Collections.emptyList();
542            }
543    
544            List<RoleMemberBo> roleMemberBoList = getStoredRoleMembersForRoleIds(roleIds, null, null);
545            List<RoleMembership> roleMemberships = new ArrayList<RoleMembership>();
546            for (RoleMemberBo roleMemberBo : roleMemberBoList) {
547                RoleMembership roleMembeship = RoleMembership.Builder.create(
548                        roleMemberBo.getRoleId(),
549                        roleMemberBo.getRoleMemberId(),
550                        roleMemberBo.getMemberId(),
551                        roleMemberBo.getMemberType(),
552                        roleMemberBo.getAttributes()).build();
553                roleMemberships.add(roleMembeship);
554            }
555            return Collections.unmodifiableList(roleMemberships);
556        }
557    
558        @Override
559        public RoleMembershipQueryResults findRoleMemberships( QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
560            incomingParamCheck(queryByCriteria, "queryByCriteria");
561    
562            GenericQueryResults<RoleMemberBo> results = getCriteriaLookupService().lookup(RoleMemberBo.class, queryByCriteria);
563    
564            RoleMembershipQueryResults.Builder builder = RoleMembershipQueryResults.Builder.create();
565            builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
566            builder.setTotalRowCount(results.getTotalRowCount());
567    
568            final List<RoleMembership.Builder> ims = new ArrayList<RoleMembership.Builder>();
569            for (RoleMemberBo bo : results.getResults()) {
570                RoleMembership.Builder roleMembership = RoleMembership.Builder.create(
571                        bo.getRoleId(),
572                        bo.getRoleMemberId(),
573                        bo.getMemberId(),
574                        bo.getMemberType(),
575                        bo.getAttributes());
576                ims.add(roleMembership);
577            }
578    
579            builder.setResults(ims);
580            return builder.build();
581        }
582    
583        @Override
584        public List<DelegateMember> getDelegationMembersByDelegationId(String delegationId) throws RiceIllegalStateException {
585            incomingParamCheck(delegationId, "delegationId");
586    
587            DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
588            if (delegateBo == null) {return Collections.emptyList();}
589    
590            return getDelegateMembersForDelegation(delegateBo);
591        }
592    
593        @Override
594        public DelegateMember getDelegationMemberByDelegationAndMemberId(String delegationId, String memberId) throws RiceIllegalStateException {
595            incomingParamCheck(delegationId, "delegationId");
596            incomingParamCheck(memberId, "memberId");
597    
598            DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
599            DelegateMemberBo delegationMember = getKimDelegationMemberImplByDelegationAndId(delegationId, memberId);
600    
601            return getDelegateCompleteInfo(delegateBo, delegationMember);
602        }
603    
604        @Override
605        public DelegateMember getDelegationMemberById(String delegationMemberId) throws RiceIllegalStateException {
606            incomingParamCheck(delegationMemberId, "delegationMemberId");
607    
608            DelegateMemberBo delegateMemberBo = getDelegateMemberBo(delegationMemberId);
609            if (delegateMemberBo == null) {
610                return null;
611            }
612    
613            DelegateTypeBo delegateBo = getKimDelegationImpl(delegateMemberBo.getDelegationId());
614    
615            return getDelegateCompleteInfo(delegateBo, delegateMemberBo);
616        }
617    
618        @Override
619        public List<RoleResponsibility> getRoleResponsibilities(String roleId) throws RiceIllegalStateException {
620            incomingParamCheck(roleId, "roleId");
621    
622            Map<String, String> criteria = new HashMap<String, String>(1);
623            criteria.put(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID, roleId);
624            List<RoleResponsibilityBo> roleResponsibilityBos = (List<RoleResponsibilityBo>)
625                    getBusinessObjectService().findMatching(RoleResponsibilityBo.class, criteria);
626            List<RoleResponsibility> roleResponsibilities = new ArrayList<RoleResponsibility>();
627    
628            for (RoleResponsibilityBo roleResponsibilityImpl : roleResponsibilityBos) {
629                roleResponsibilities.add(RoleResponsibilityBo.to(roleResponsibilityImpl));
630            }
631            return Collections.unmodifiableList(roleResponsibilities);
632        }
633    
634        @Override
635        public DelegateType getDelegateTypeByRoleIdAndDelegateTypeCode(String roleId, DelegationType delegationType) throws RiceIllegalStateException {
636            incomingParamCheck(roleId, "roleId");
637            incomingParamCheck(delegationType, "delegationType");
638    
639            DelegateTypeBo delegateBo = getDelegationOfType(roleId, delegationType);
640            return DelegateTypeBo.to(delegateBo);
641        }
642    
643        @Override
644        public DelegateType getDelegateTypeByDelegationId(String delegationId) throws RiceIllegalStateException {
645            incomingParamCheck(delegationId, "delegationId");
646    
647            DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
648            return DelegateTypeBo.to(delegateBo);
649        }
650    
651        protected List<RoleMembership> getRoleMembers(List<String> roleIds, Map<String, String> qualification, boolean followDelegations, Set<String> foundRoleTypeMembers) {
652            List<RoleMembership> results = new ArrayList<RoleMembership>();
653            Set<String> allRoleIds = new HashSet<String>();
654            for (String roleId : roleIds) {
655                if (isRoleActive(roleId)) {
656                    allRoleIds.add(roleId);
657                }
658            }
659            // short-circuit if no roles match
660            if (allRoleIds.isEmpty()) {
661                return Collections.emptyList();
662            }
663            Set<String> matchingRoleIds = new HashSet<String>(allRoleIds.size());
664            // for efficiency, retrieve all roles and store in a map
665            Map<String, RoleBo> roles = getRoleBoMap(allRoleIds);
666    
667            List<String> copyRoleIds = new ArrayList<String>(allRoleIds);
668            List<RoleMemberBo> rms = new ArrayList<RoleMemberBo>();
669    
670            for (String roleId : allRoleIds) {
671                RoleTypeService roleTypeService = getRoleTypeService(roleId);
672                if (roleTypeService != null) {
673                    List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
674                    if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
675                        copyRoleIds.remove(roleId);
676                        rms.addAll(getStoredRoleMembersForRoleIds(Collections.singletonList(roleId), null, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
677                    }
678                }
679            }
680            if (CollectionUtils.isNotEmpty(copyRoleIds)) {
681                rms.addAll(getStoredRoleMembersForRoleIds(copyRoleIds, null, null));
682            }
683    
684            // build a map of role ID to membership information
685            // this will be used for later qualification checks
686            Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
687            for (RoleMemberBo roleMemberBo : rms) {
688                RoleMembership mi = RoleMembership.Builder.create(
689                        roleMemberBo.getRoleId(),
690                        roleMemberBo.getRoleMemberId(),
691                        roleMemberBo.getMemberId(),
692                        roleMemberBo.getMemberType(),
693                        roleMemberBo.getAttributes()).build();
694    
695                // if the qualification check does not need to be made, just add the result
696                if ((qualification == null || qualification.isEmpty()) || getRoleTypeService(roleMemberBo.getRoleId()) == null) {
697                    if (MemberType.ROLE.equals(roleMemberBo.getMemberType())) {
698                        // if a role member type, do a non-recursive role member check
699                        // to obtain the group and principal members of that role
700                        // given the qualification
701                        Map<String, String> nestedRoleQualification = qualification;
702                        if (getRoleTypeService(roleMemberBo.getRoleId()) != null) {
703                            // get the member role object
704                            RoleBo memberRole = getRoleBo(mi.getMemberId());
705                            nestedRoleQualification = getRoleTypeService(roleMemberBo.getRoleId())
706                                    .convertQualificationForMemberRoles(
707                                            roles.get(roleMemberBo.getRoleId()).getNamespaceCode(),
708                                            roles.get(roleMemberBo.getRoleId()).getName(),
709                                            memberRole.getNamespaceCode(),
710                                            memberRole.getName(),
711                                            qualification);
712                        }
713                        if (isRoleActive(roleMemberBo.getRoleId())) {
714                            Collection<RoleMembership> nestedRoleMembers = getNestedRoleMembers(nestedRoleQualification, mi, foundRoleTypeMembers);
715                            if (!nestedRoleMembers.isEmpty()) {
716                                results.addAll(nestedRoleMembers);
717                                matchingRoleIds.add(roleMemberBo.getRoleId());
718                            }
719                        }
720                    } else { // not a role member type
721                        results.add(mi);
722                        matchingRoleIds.add(roleMemberBo.getRoleId());
723                    }
724                    matchingRoleIds.add(roleMemberBo.getRoleId());
725                } else {
726                    List<RoleMembership> lrmi = roleIdToMembershipMap.get(mi.getRoleId());
727                    if (lrmi == null) {
728                        lrmi = new ArrayList<RoleMembership>();
729                        roleIdToMembershipMap.put(mi.getRoleId(), lrmi);
730                    }
731                    lrmi.add(mi);
732                }
733            }
734            // if there is anything in the role to membership map, we need to check the role type services
735            // for those entries
736            if (!roleIdToMembershipMap.isEmpty()) {
737                // for each role, send in all the qualifiers for that role to the type service
738                // for evaluation, the service will return those which match
739                for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
740                    //it is possible that the the roleTypeService is coming from a remote application
741                    // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
742                    try {
743                        RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
744                        List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification,
745                                entry.getValue());
746                        // loop over the matching entries, adding them to the results
747                        for (RoleMembership roleMemberships : matchingMembers) {
748                            if (MemberType.ROLE.equals(roleMemberships.getMemberType())) {
749                                // if a role member type, do a non-recursive role member check
750                                // to obtain the group and principal members of that role
751                                // given the qualification
752                                // get the member role object
753                                RoleBo memberRole = getRoleBo(roleMemberships.getMemberId());
754                                if (memberRole.isActive()) {
755                                    Map<String, String> nestedRoleQualification = roleTypeService.convertQualificationForMemberRoles(
756                                            roles.get(roleMemberships.getRoleId()).getNamespaceCode(),
757                                            roles.get(roleMemberships.getRoleId()).getName(),
758                                            memberRole.getNamespaceCode(),
759                                            memberRole.getName(),
760                                            qualification);
761                                    Collection<RoleMembership> nestedRoleMembers = getNestedRoleMembers(nestedRoleQualification, roleMemberships, foundRoleTypeMembers);
762                                    if (!nestedRoleMembers.isEmpty()) {
763                                        results.addAll(nestedRoleMembers);
764                                        matchingRoleIds.add(roleMemberships.getRoleId());
765                                    }
766                                }
767                            } else { // not a role member
768                                results.add(roleMemberships);
769                                matchingRoleIds.add(roleMemberships.getRoleId());
770                            }
771                        }
772                    } catch (Exception ex) {
773                        LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
774                    }
775                }
776            }
777    
778            // handle application roles
779            for ( String roleId : allRoleIds ) {
780                    RoleTypeService roleTypeService = getRoleTypeService( roleId );
781                            RoleBo role = roles.get( roleId );
782                    // check if an application role
783                try {
784                            if ( isApplicationRoleType(role.getKimTypeId(), roleTypeService) ) {
785                        // for each application role, get the list of principals and groups which are in that role given the qualification (per the role type service)
786                                    List<RoleMembership> roleMembers = roleTypeService.getRoleMembersFromApplicationRole(role.getNamespaceCode(), role.getName(), qualification);
787                                    if ( !roleMembers.isEmpty()  ) {
788                                            matchingRoleIds.add( roleId );
789                                    }
790                                    for ( RoleMembership rm : roleMembers ) {
791                            RoleMembership.Builder builder = RoleMembership.Builder.create(rm);
792                            builder.setRoleId(roleId);
793                            builder.setRoleMemberId("*");
794                            results.add(builder.build());
795                                    }
796                            }
797                } catch (Exception ex) {
798                    LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleId, ex);
799                }
800            }
801    
802            if ( followDelegations && !matchingRoleIds.isEmpty() ) {
803                    // we have a list of RoleMembershipInfo objects
804                    // need to get delegations for distinct list of roles in that list
805                    Map<String, DelegateTypeBo> delegationIdToDelegationMap = getStoredDelegationImplMapFromRoleIds(matchingRoleIds);
806                if (!delegationIdToDelegationMap.isEmpty()) {
807                    List<RoleMembership.Builder> membershipsWithDelegations =
808                            applyDelegationsToRoleMembers(results, delegationIdToDelegationMap.values(), qualification);
809                    resolveDelegationMemberRoles(membershipsWithDelegations, qualification, foundRoleTypeMembers);
810                    results = ModelObjectUtils.buildImmutableCopy(membershipsWithDelegations);
811                }
812            }
813    
814            return Collections.unmodifiableList(results);
815        }
816    
817        /**
818         * Checks each of the result records to determine if there are potentially applicable delegation members for that
819         * role membership.  If there are, applicable delegations and members will be linked to the RoleMemberships in the
820         * given list.  An updated list will be returned from this method which includes the appropriate linked delegations.
821         */
822        protected List<RoleMembership.Builder> applyDelegationsToRoleMembers(List<RoleMembership> roleMemberships,
823                Collection<DelegateTypeBo> delegations, Map<String, String> qualification) {
824            MultiValueMap<String, String> roleIdToRoleMembershipIds = new LinkedMultiValueMap<String, String>();
825            Map<String, RoleMembership.Builder> roleMembershipIdToBuilder = new HashMap<String, RoleMembership.Builder>();
826            List<RoleMembership.Builder> roleMembershipBuilders = new ArrayList<RoleMembership.Builder>();
827            // to make our algorithm less painful, let's do some indexing and load the given list of RoleMemberships into
828            // builders
829            for (RoleMembership roleMembership : roleMemberships) {
830                roleIdToRoleMembershipIds.add(roleMembership.getRoleId(), roleMembership.getRoleMemberId());
831                RoleMembership.Builder builder = RoleMembership.Builder.create(roleMembership);
832                roleMembershipBuilders.add(builder);
833                roleMembershipIdToBuilder.put(roleMembership.getRoleMemberId(), builder);
834            }
835            for (DelegateTypeBo delegation : delegations) {
836                // determine the candidate role memberships where this delegation can be mapped
837                List<String> candidateRoleMembershipIds = roleIdToRoleMembershipIds.get(delegation.getRoleId());
838                if (CollectionUtils.isNotEmpty(candidateRoleMembershipIds)) {
839                    DelegationTypeService delegationTypeService = getDelegationTypeService(delegation.getDelegationId());
840                    for (DelegateMemberBo delegationMember : delegation.getMembers()) {
841                        // Make sure that the delegation member is active
842                            if (delegationMember.isActive(DateTime.now()) && (delegationTypeService == null ||
843                                delegationTypeService.doesDelegationQualifierMatchQualification(qualification, delegationMember.getQualifier()))) {
844                            DelegateMember.Builder delegateMemberBuilder = DelegateMember.Builder.create(delegationMember);
845                            // if the member has no role member id, check qualifications and apply to all matching role memberships on the role
846                                if (StringUtils.isBlank(delegationMember.getRoleMemberId())) {
847                                RoleTypeService roleTypeService = getRoleTypeService(delegation.getRoleId());
848                                for (String roleMembershipId : candidateRoleMembershipIds) {
849                                    RoleMembership.Builder roleMembershipBuilder = roleMembershipIdToBuilder.get(roleMembershipId);
850                                    if (roleTypeService == null || roleTypeService.doesRoleQualifierMatchQualification(roleMembershipBuilder.getQualifier(), delegationMember.getQualifier())) {
851                                        linkDelegateToRoleMembership(delegation, delegateMemberBuilder, roleMembershipBuilder);
852                                    }
853                                }
854                            } else if (candidateRoleMembershipIds.contains(delegationMember.getRoleMemberId())) {
855                                RoleMembership.Builder roleMembershipBuilder = roleMembershipIdToBuilder.get(delegationMember.getRoleMemberId());
856                                linkDelegateToRoleMembership(delegation, delegateMemberBuilder, roleMembershipBuilder);
857                            }
858                        }
859                    }
860                }
861            }
862            return roleMembershipBuilders;
863        }
864    
865        protected void linkDelegateToRoleMembership(DelegateTypeBo delegation, DelegateMember.Builder delegateMemberBuilder,
866                RoleMembership.Builder roleMembershipBuilder) {
867            DelegateType.Builder delegateBuilder = null;
868            for(DelegateType.Builder existingDelegateBuilder : roleMembershipBuilder.getDelegates()) {
869                if (existingDelegateBuilder.getDelegationId().equals(delegation.getDelegationId())) {
870                    delegateBuilder = existingDelegateBuilder;
871                }
872            }
873            if (delegateBuilder == null) {
874                delegateBuilder = DelegateType.Builder.create(delegation);
875                delegateBuilder.setMembers(new ArrayList<DelegateMember.Builder>());
876                roleMembershipBuilder.getDelegates().add(delegateBuilder);
877            }
878            delegateBuilder.getMembers().add(delegateMemberBuilder);
879    
880        }
881    
882        /**
883         * Once the delegations for a RoleMembershipInfo object have been determined,
884         * any "role" member types need to be resolved into groups and principals so that
885         * further KIM requests are not needed.
886         */
887        protected void resolveDelegationMemberRoles(List<RoleMembership.Builder> membershipBuilders,
888                Map<String, String> qualification, Set<String> foundRoleTypeMembers) {
889            // check delegations assigned to this role
890            for (RoleMembership.Builder roleMembership : membershipBuilders) {
891                // the applicable delegation IDs will already be set in the RoleMembership.Builder
892                // this code examines those delegations and obtains the member groups and principals
893                for (DelegateType.Builder delegation : roleMembership.getDelegates()) {
894                    List<DelegateMember.Builder> newMembers = new ArrayList<DelegateMember.Builder>();
895                    for (DelegateMember.Builder member : delegation.getMembers()) {
896                        if (MemberType.ROLE.equals(member.getType())) {
897                            // loop over delegation roles and extract the role IDs where the qualifications match
898                            Collection<RoleMembership> delegateMembers = getRoleMembers(Collections.singletonList(
899                                    member.getMemberId()), qualification, false, foundRoleTypeMembers);
900                            // loop over the role members and create the needed DelegationMember builders
901                            for (RoleMembership rmi : delegateMembers) {
902                                DelegateMember.Builder delegateMember = DelegateMember.Builder.create(member);
903                                delegateMember.setMemberId(rmi.getMemberId());
904                                delegateMember.setType(rmi.getMemberType());
905                                newMembers.add(delegateMember);
906                            }
907                        } else {
908                            newMembers.add(member);
909                        }
910                    }
911                    delegation.setMembers(newMembers);
912                }
913            }
914        }
915    
916        protected boolean principalHasRole(String principalId, List<String> roleIds, Map<String, String> qualification, boolean checkDelegations) {
917            if (StringUtils.isBlank(principalId)) {
918                return false;
919            }
920            Set<String> allRoleIds = new HashSet<String>();
921            // remove inactive roles
922            for (String roleId : roleIds) {
923                if (isRoleActive(roleId)) {
924                    allRoleIds.add(roleId);
925                }
926            }
927            // short-circuit if no roles match
928            if (allRoleIds.isEmpty()) {
929                return false;
930            }
931            // for efficiency, retrieve all roles and store in a map
932            Map<String, RoleBo> roles = getRoleBoMap(allRoleIds);
933            // get all roles to which the principal is assigned
934            List<String> copyRoleIds = new ArrayList<String>(allRoleIds);
935            List<RoleMemberBo> rps = new ArrayList<RoleMemberBo>();
936    
937            for (String roleId : allRoleIds) {
938                RoleTypeService roleTypeService = getRoleTypeService(roleId);
939                if (roleTypeService != null) {
940                    List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
941                    if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
942                        copyRoleIds.remove(roleId);
943                        rps.addAll(getStoredRolePrincipalsForPrincipalIdAndRoleIds(Collections.singletonList(roleId), principalId, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
944                    }
945                }
946            }
947            if (CollectionUtils.isNotEmpty(copyRoleIds)) {
948                rps.addAll(getStoredRolePrincipalsForPrincipalIdAndRoleIds(copyRoleIds, principalId, null));
949            }
950    
951            // if the qualification is null and the role list is not, then any role in the list will match
952            // so since the role ID list is not blank, we can return true at this point
953            if ((qualification == null || qualification.isEmpty()) && !rps.isEmpty()) {
954                return true;
955            }
956    
957            // check each membership to see if the principal matches
958    
959            // build a map of role ID to membership information
960            // this will be used for later qualification checks
961            Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
962            if (getRoleIdToMembershipMap(roleIdToMembershipMap, rps)) {
963                return true;
964            }
965    
966            // perform the checks against the role type services
967            for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
968                try {
969                    RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
970                    if (!roleTypeService.getMatchingRoleMemberships(qualification, entry.getValue()).isEmpty()) {
971                        return true;
972                    }
973                } catch (Exception ex) {
974                    LOG.warn("Unable to find role type service with id: " + entry.getKey());
975                }
976            }
977    
978            // find the groups that the principal belongs to
979            List<String> principalGroupIds = getGroupService().getGroupIdsByPrincipalId(principalId);
980            // find the role/group associations
981            if (!principalGroupIds.isEmpty()) {
982                List<RoleMemberBo> rgs = getStoredRoleGroupsUsingExactMatchOnQualification(principalGroupIds, allRoleIds, qualification);
983                roleIdToMembershipMap.clear(); // clear the role/member map for further use
984                if (getRoleIdToMembershipMap(roleIdToMembershipMap, rgs)) {
985                    return true;
986                }
987    
988                // perform the checks against the role type services
989                for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
990                    try {
991                        RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
992                        if (!roleTypeService.getMatchingRoleMemberships(qualification, entry.getValue()).isEmpty()) {
993                            return true;
994                        }
995                    } catch (Exception ex) {
996                        LOG.warn("Unable to find role type service with id: " + entry.getKey(), ex);
997                    }
998                }
999            }
1000    
1001            // check member roles
1002            // first, check that the qualifiers on the role membership match
1003            // then, perform a principalHasRole on the embedded role
1004            List<RoleMemberBo> roleMemberBos = getStoredRoleMembersForRoleIds(roleIds, MemberType.ROLE.getCode(), null);
1005            for (RoleMemberBo roleMemberBo : roleMemberBos) {
1006                RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
1007                if (roleTypeService != null) {
1008                    //it is possible that the the roleTypeService is coming from a remote application
1009                    // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1010                    try {
1011                        if (roleTypeService.doesRoleQualifierMatchQualification(qualification, roleMemberBo.getAttributes())) {
1012                            RoleBo memberRole = getRoleBo(roleMemberBo.getMemberId());
1013                            Map<String, String> nestedRoleQualification = roleTypeService.convertQualificationForMemberRoles(
1014                                    roles.get(roleMemberBo.getRoleId()).getNamespaceCode(),
1015                                    roles.get(roleMemberBo.getRoleId()).getName(),
1016                                    memberRole.getNamespaceCode(),
1017                                    memberRole.getName(),
1018                                    qualification);
1019                            ArrayList<String> roleIdTempList = new ArrayList<String>(1);
1020                            roleIdTempList.add(roleMemberBo.getMemberId());
1021                            if (principalHasRole(principalId, roleIdTempList, nestedRoleQualification, true)) {
1022                                return true;
1023                            }
1024                        }
1025                    } catch (Exception ex) {
1026                        LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleMemberBo.getRoleId(), ex);
1027                        //return false;
1028                    }
1029                } else {
1030                    // no qualifiers - role is always used - check membership
1031                    ArrayList<String> roleIdTempList = new ArrayList<String>(1);
1032                    roleIdTempList.add(roleMemberBo.getMemberId());
1033                    // no role type service, so can't convert qualification - just pass as is
1034                    if (principalHasRole(principalId, roleIdTempList, qualification, true)) {
1035                        return true;
1036                    }
1037                }
1038    
1039            }
1040    
1041    
1042            // check for application roles and extract principals and groups from that - then check them against the
1043            // role type service passing in the qualification and principal - the qualifier comes from the
1044            // external system (application)
1045    
1046            // loop over the allRoleIds list
1047            for (String roleId : allRoleIds) {
1048                RoleBo role = roles.get(roleId);
1049                RoleTypeService roleTypeService = getRoleTypeService(roleId);
1050                // check if an application role
1051                //it is possible that the the roleTypeService is coming from a remote application
1052                // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1053                try {
1054                    if (isApplicationRoleType(role.getKimTypeId(), roleTypeService)) {
1055                        if (roleTypeService.hasApplicationRole(principalId, principalGroupIds, role.getNamespaceCode(), role.getName(), qualification)) {
1056                            return true;
1057                        }
1058                    }
1059                } catch (Exception ex) {
1060                    LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleId, ex);
1061                    //return false;
1062                }
1063            }
1064    
1065            // delegations
1066            if (checkDelegations) {
1067                if (matchesOnDelegation(allRoleIds, principalId, principalGroupIds, qualification)) {
1068                    return true;
1069                }
1070            }
1071    
1072            // NOTE: this logic is a little different from the getRoleMembers method
1073            // If there is no primary (matching non-delegate), this method will still return true
1074            return false;
1075        }
1076    
1077    
1078        protected boolean isApplicationRoleType(String roleTypeId, RoleTypeService service) {
1079            return service != null && service.isApplicationRoleType();
1080        }
1081    
1082        /**
1083         * Support method for principalHasRole.  Checks delegations on the passed in roles for the given principal and groups.  (It's assumed that the principal
1084         * belongs to the given groups.)
1085         * <p/>
1086         * Delegation checks are mostly the same as role checks except that the delegateBo itself is qualified against the original role (like a RolePrincipal
1087         * or RoleGroup.)  And then, the members of that delegateBo may have additional qualifiers which are not part of the original role qualifiers.
1088         * <p/>
1089         * For example:
1090         * <p/>
1091         * A role could be qualified by organization.  So, there is a person in the organization with primary authority for that org.  But, then they delegate authority
1092         * for that organization (not their authority - the delegateBo is attached to the org.)  So, in this case the delegateBo has a qualifier of the organization
1093         * when it is attached to the role.
1094         * <p/>
1095         * The principals then attached to that delegateBo (which is specific to the organization), may have additional qualifiers.
1096         * For Example: dollar amount range, effective dates, document types.
1097         * As a subsequent step, those qualifiers are checked against the qualification passed in from the client.
1098         */
1099        protected boolean matchesOnDelegation(Set<String> allRoleIds, String principalId, List<String> principalGroupIds, Map<String, String> qualification) {
1100            // get the list of delegations for the roles
1101            Map<String, DelegateTypeBo> delegations = getStoredDelegationImplMapFromRoleIds(allRoleIds);
1102            // loop over the delegations - determine those which need to be inspected more directly
1103            for (DelegateTypeBo delegation : delegations.values()) {
1104                // check if each one matches via the original role type service
1105                if (!delegation.isActive()) {
1106                    continue;
1107                }
1108                RoleTypeService roleTypeService = getRoleTypeService(delegation.getRoleId());
1109                for (DelegateMemberBo delegateMemberBo : delegation.getMembers()) {
1110                    if (!delegateMemberBo.isActive(new Timestamp(new Date().getTime()))) {
1111                        continue;
1112                    }
1113                    // check if this delegateBo record applies to the given person
1114                    if (MemberType.PRINCIPAL.equals(delegateMemberBo.getType())
1115                            && !delegateMemberBo.getMemberId().equals(principalId)) {
1116                        continue; // no match on principal
1117                    }
1118                    // or if a group
1119                    if (MemberType.GROUP.equals(delegateMemberBo.getType())
1120                            && !principalGroupIds.contains(delegateMemberBo.getMemberId())) {
1121                        continue; // no match on group
1122                    }
1123                    // or if a role
1124                    if (MemberType.ROLE.equals(delegateMemberBo.getType())
1125                            && !principalHasRole(principalId, Collections.singletonList(delegateMemberBo.getMemberId()), qualification, false)) {
1126                        continue; // no match on role
1127                    }
1128                    // OK, the member matches the current user, now check the qualifications
1129    
1130                    // NOTE: this compare is slightly different than the member enumeration
1131                    // since the requested qualifier is always being used rather than
1132                    // the role qualifier for the member (which is not available)
1133    
1134                    //it is possible that the the roleTypeService is coming from a remote application
1135                    // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1136                    try {
1137                        //TODO: remove reference to Attributes here and use Attributes instead.
1138                        if (roleTypeService != null && !roleTypeService.doesRoleQualifierMatchQualification(qualification, delegateMemberBo.getQualifier())) {
1139                            continue; // no match - skip to next record
1140                        }
1141                    } catch (Exception ex) {
1142                        LOG.warn("Unable to call doesRoleQualifierMatchQualification on role type service for role Id: " + delegation.getRoleId() + " / " + qualification + " / " + delegateMemberBo.getQualifier(), ex);
1143                        continue;
1144                    }
1145    
1146                    // role service matches this qualifier
1147                    // now try the delegateBo service
1148                    DelegationTypeService delegationTypeService = getDelegationTypeService(delegateMemberBo.getDelegationId());
1149                    // QUESTION: does the qualifier map need to be merged with the main delegateBo qualification?
1150                    if (delegationTypeService != null && !delegationTypeService.doesDelegationQualifierMatchQualification(qualification, delegateMemberBo.getQualifier())) {
1151                        continue; // no match - skip to next record
1152                    }
1153                    // check if a role member ID is present on the delegateBo record
1154                    // if so, check that the original role member would match the given qualifiers
1155                    if (StringUtils.isNotBlank(delegateMemberBo.getRoleMemberId())) {
1156                        RoleMemberBo rm = getRoleMemberBo(delegateMemberBo.getRoleMemberId());
1157                        if (rm != null) {
1158                            // check that the original role member's is active and that their
1159                            // qualifier would have matched this request's
1160                            // qualifications (that the original person would have the permission/responsibility
1161                            // for an action)
1162                            // this prevents a role-membership based delegateBo from surviving the inactivation/
1163                            // changing of the main person's role membership
1164                            if (!rm.isActive(new Timestamp(new Date().getTime()))) {
1165                                continue;
1166                            }
1167                            Map<String, String> roleQualifier = rm.getAttributes();
1168                            //it is possible that the the roleTypeService is coming from a remote application
1169                            // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1170                            try {
1171                                if (roleTypeService != null && !roleTypeService.doesRoleQualifierMatchQualification(qualification, roleQualifier)) {
1172                                    continue;
1173                                }
1174                            } catch (Exception ex) {
1175                                LOG.warn("Unable to call doesRoleQualifierMatchQualification on role type service for role Id: " + delegation.getRoleId() + " / " + qualification + " / " + roleQualifier, ex);
1176                                continue;
1177                            }
1178                        } else {
1179                            LOG.warn("Unknown role member ID cited in the delegateBo member table:");
1180                            LOG.warn("       assignedToId: " + delegateMemberBo.getDelegationMemberId() + " / roleMemberId: " + delegateMemberBo.getRoleMemberId());
1181                        }
1182                    }
1183                    // all tests passed, return true
1184                    return true;
1185                }
1186            }
1187            return false;
1188        }
1189    
1190        /**
1191         * Helper method used by principalHasRole to build the role ID -> list of members map.
1192         *
1193         * @return <b>true</b> if no further checks are needed because no role service is defined
1194         */
1195        protected boolean getRoleIdToMembershipMap(Map<String, List<RoleMembership>> roleIdToMembershipMap, List<RoleMemberBo> roleMembers) {
1196            for (RoleMemberBo roleMemberBo : roleMembers) {
1197                RoleMembership roleMembership = RoleMembership.Builder.create(
1198                        roleMemberBo.getRoleId(),
1199                        roleMemberBo.getRoleMemberId(),
1200                        roleMemberBo.getMemberId(),
1201                        roleMemberBo.getMemberType(),
1202                        roleMemberBo.getAttributes()).build();
1203    
1204                // if the role type service is null, assume that all qualifiers match
1205                if (getRoleTypeService(roleMemberBo.getRoleId()) == null) {
1206                    return true;
1207                }
1208                List<RoleMembership> lrmi = roleIdToMembershipMap.get(roleMembership.getRoleId());
1209                if (lrmi == null) {
1210                    lrmi = new ArrayList<RoleMembership>();
1211                    roleIdToMembershipMap.put(roleMembership.getRoleId(), lrmi);
1212                }
1213                lrmi.add(roleMembership);
1214            }
1215            return false;
1216        }
1217    
1218        /**
1219         * Retrieves a KimDelegationImpl object by its ID. If the delegateBo already exists in the cache, this method will return the cached
1220         * version; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
1221         */
1222        protected DelegateTypeBo getKimDelegationImpl(String delegationId) {
1223            if (StringUtils.isBlank(delegationId)) {
1224                return null;
1225            }
1226    
1227            return getBusinessObjectService().findByPrimaryKey(DelegateTypeBo.class,
1228                    Collections.singletonMap(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId));
1229        }
1230    
1231        protected DelegationTypeService getDelegationTypeService(String delegationId) {
1232            DelegationTypeService service = null;
1233            DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
1234            KimType delegationType = KimApiServiceLocator.getKimTypeInfoService().getKimType(delegateBo.getKimTypeId());
1235            if (delegationType != null) {
1236                KimTypeService tempService = KimFrameworkServiceLocator.getKimTypeService(delegationType);
1237                if (tempService != null && tempService instanceof DelegationTypeService) {
1238                    service = (DelegationTypeService) tempService;
1239                } else {
1240                    LOG.error("Service returned for type " + delegationType + "(" + delegationType.getName() + ") was not a DelegationTypeService.  Was a " + (tempService != null ? tempService.getClass() : "(null)"));
1241                }
1242            } else { // delegateBo has no type - default to role type if possible
1243                RoleTypeService roleTypeService = getRoleTypeService(delegateBo.getRoleId());
1244                if (roleTypeService != null && roleTypeService instanceof DelegationTypeService) {
1245                    service = (DelegationTypeService) roleTypeService;
1246                }
1247            }
1248            return service;
1249        }
1250    
1251        protected Collection<RoleMembership> getNestedRoleMembers(Map<String, String> qualification, RoleMembership rm, Set<String> foundRoleTypeMembers) {
1252            // If this role has already been traversed, skip it
1253            if (foundRoleTypeMembers.contains(rm.getMemberId())) {
1254                return new ArrayList<RoleMembership>();  // return an empty list
1255            }
1256            foundRoleTypeMembers.add(rm.getMemberId());
1257    
1258            ArrayList<String> roleIdList = new ArrayList<String>(1);
1259            roleIdList.add(rm.getMemberId());
1260    
1261            // get the list of members from the nested role - ignore delegations on those sub-roles
1262            Collection<RoleMembership> currentNestedRoleMembers = getRoleMembers(roleIdList, qualification, false, foundRoleTypeMembers);
1263    
1264            // add the roles whose members matched to the list for delegateBo checks later
1265            Collection<RoleMembership> returnRoleMembers = new ArrayList<RoleMembership>();
1266            for (RoleMembership roleMembership : currentNestedRoleMembers) {
1267                RoleMembership.Builder rmBuilder = RoleMembership.Builder.create(roleMembership);
1268    
1269                // use the member ID of the parent role (needed for responsibility joining)
1270                rmBuilder.setRoleMemberId(rm.getRoleMemberId());
1271                // store the role ID, so we know where this member actually came from
1272                rmBuilder.setRoleId(rm.getRoleId());
1273                rmBuilder.setEmbeddedRoleId(rm.getMemberId());
1274                returnRoleMembers.add(rmBuilder.build());
1275            }
1276            return returnRoleMembers;
1277        }
1278    
1279        /**
1280         * Retrieves a KimDelegationMemberImpl object by its ID and the ID of the delegation it belongs to. If the delegation member exists in the cache,
1281         * this method will return the cached one; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
1282         */
1283        protected DelegateMemberBo getKimDelegationMemberImplByDelegationAndId(String delegationId, String delegationMemberId) {
1284            if (StringUtils.isBlank(delegationId) || StringUtils.isBlank(delegationMemberId)) {
1285                return null;
1286            }
1287    
1288            Map<String, String> searchCriteria = new HashMap<String, String>();
1289            searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId);
1290            searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMemberId);
1291            List<DelegateMemberBo> memberList =
1292                    (List<DelegateMemberBo>) getBusinessObjectService().findMatching(DelegateMemberBo.class, searchCriteria);
1293            if (memberList != null && !memberList.isEmpty()) {
1294                return memberList.get(0);
1295            }
1296            return null;
1297        }
1298    
1299        private List<RoleMemberBo> getStoredRoleMembersUsingExactMatchOnQualification(String principalId, List<String> groupIds, List<String> roleIds, Map<String, String> qualification) {
1300            List<String> copyRoleIds = new ArrayList<String>(roleIds);
1301            List<RoleMemberBo> roleMemberBoList = new ArrayList<RoleMemberBo>();
1302    
1303            for (String roleId : roleIds) {
1304                RoleTypeService roleTypeService = getRoleTypeService(roleId);
1305                if (roleTypeService != null) {
1306                    List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
1307                    if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
1308                        copyRoleIds.remove(roleId);
1309                        roleMemberBoList.addAll(getStoredRoleMembersForRoleIdsWithFilters(Collections.singletonList(roleId), principalId, groupIds, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
1310                    }
1311                }
1312            }
1313            if (CollectionUtils.isNotEmpty(copyRoleIds)) {
1314                roleMemberBoList.addAll(getStoredRoleMembersForRoleIdsWithFilters(copyRoleIds, principalId, groupIds, null));
1315            }
1316            return roleMemberBoList;
1317        }
1318    
1319        private List<RoleMemberBo> getStoredRoleGroupsUsingExactMatchOnQualification(List<String> groupIds, Set<String> roleIds, Map<String, String> qualification) {
1320            List<String> copyRoleIds = new ArrayList<String>(roleIds);
1321            List<RoleMemberBo> roleMemberBos = new ArrayList<RoleMemberBo>();
1322    
1323            for (String roleId : roleIds) {
1324                RoleTypeService roleTypeService = getRoleTypeService(roleId);
1325                if (roleTypeService != null) {
1326                    List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
1327                    if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
1328                        copyRoleIds.remove(roleId);
1329                        roleMemberBos.addAll(getStoredRoleGroupsForGroupIdsAndRoleIds(Collections.singletonList(roleId), groupIds, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
1330                    }
1331                }
1332            }
1333            if (CollectionUtils.isNotEmpty(copyRoleIds)) {
1334                roleMemberBos.addAll(getStoredRoleGroupsForGroupIdsAndRoleIds(copyRoleIds, groupIds, null));
1335            }
1336            return roleMemberBos;
1337        }
1338    
1339        private List<DelegateMember> getDelegateMembersForDelegation(DelegateTypeBo delegateBo) {
1340            if (delegateBo == null || delegateBo.getMembers() == null) {return null;}
1341            List<DelegateMember> delegateMembersReturnList = new ArrayList<DelegateMember>();
1342            for (DelegateMemberBo delegateMemberBo : delegateBo.getMembers()) {
1343                //FIXME: What is up with this!?!
1344                DelegateMember delegateMember = getDelegateCompleteInfo(delegateBo, delegateMemberBo);
1345    
1346                delegateMembersReturnList.add(DelegateMemberBo.to(delegateMemberBo));
1347            }
1348            return Collections.unmodifiableList(delegateMembersReturnList);
1349        }
1350    
1351        private DelegateMember getDelegateCompleteInfo(DelegateTypeBo delegateBo, DelegateMemberBo delegateMemberBo) {
1352            if (delegateBo == null || delegateMemberBo == null) {return null;}
1353    
1354            DelegateMember.Builder delegateMemberBuilder = DelegateMember.Builder.create(delegateMemberBo);
1355            delegateMemberBuilder.setType(delegateMemberBo.getType());
1356            return delegateMemberBuilder.build();
1357        }
1358    
1359        @Override
1360        public void assignPrincipalToRole(String principalId,
1361                String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1362            incomingParamCheck(principalId, "principalId");
1363            incomingParamCheck(namespaceCode, "namespaceCode");
1364            incomingParamCheck(roleName, "roleName");
1365            incomingParamCheck(qualifier, "qualifier");
1366    
1367            // look up the role
1368            RoleBo role = getRoleBoByName(namespaceCode, roleName);
1369            role.refreshReferenceObject("members");
1370    
1371            // check that identical member does not already exist
1372            if ( doAnyMemberRecordsMatchByExactQualifier(role, principalId, memberTypeToRoleDaoActionMap.get(MemberType.PRINCIPAL.getCode()), qualifier) ||
1373                            doAnyMemberRecordsMatch( role.getMembers(), principalId, MemberType.PRINCIPAL.getCode(), qualifier ) ) {
1374                    return;
1375            }
1376            // create the new role member object
1377            RoleMemberBo newRoleMember = new RoleMemberBo();
1378    
1379            newRoleMember.setRoleId(role.getId());
1380            newRoleMember.setMemberId(principalId);
1381            newRoleMember.setMemberType(MemberType.PRINCIPAL);
1382    
1383            // build role member attribute objects from the given Map<String, String>
1384            addMemberAttributeData(newRoleMember, qualifier, role.getKimTypeId());
1385    
1386            // add row to member table
1387            // When members are added to roles, clients must be notified.
1388            getResponsibilityInternalService().saveRoleMember(newRoleMember);
1389        }
1390    
1391        @Override
1392        public void assignGroupToRole(String groupId, String namespaceCode,
1393                String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1394            incomingParamCheck(groupId, "groupId");
1395            incomingParamCheck(namespaceCode, "namespaceCode");
1396            incomingParamCheck(roleName, "roleName");
1397            incomingParamCheck(qualifier, "qualifier");
1398    
1399            // look up the role
1400            RoleBo role = getRoleBoByName(namespaceCode, roleName);
1401            // check that identical member does not already exist
1402            if ( doAnyMemberRecordsMatchByExactQualifier(role, groupId, memberTypeToRoleDaoActionMap.get(MemberType.GROUP.getCode()), qualifier) ||
1403                            doAnyMemberRecordsMatch( role.getMembers(), groupId, MemberType.GROUP.getCode(), qualifier ) ) {
1404                    return;
1405            }
1406            // create the new role member object
1407            RoleMemberBo newRoleMember = new RoleMemberBo();
1408            newRoleMember.setRoleId(role.getId());
1409            newRoleMember.setMemberId(groupId);
1410            newRoleMember.setMemberType(MemberType.GROUP);
1411    
1412            // build role member attribute objects from the given Map<String, String>
1413            addMemberAttributeData(newRoleMember, qualifier, role.getKimTypeId());
1414    
1415            // When members are added to roles, clients must be notified.
1416            getResponsibilityInternalService().saveRoleMember(newRoleMember);
1417        }
1418    
1419        @Override
1420        public void assignRoleToRole(String roleId,
1421                String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1422            incomingParamCheck(roleId, "roleId");
1423            incomingParamCheck(namespaceCode, "namespaceCode");
1424            incomingParamCheck(roleName, "roleName");
1425            incomingParamCheck(qualifier, "qualifier");
1426    
1427            // look up the roleBo
1428            RoleBo roleBo = getRoleBoByName(namespaceCode, roleName);
1429            // check that identical member does not already exist
1430            if ( doAnyMemberRecordsMatchByExactQualifier(roleBo, roleId, memberTypeToRoleDaoActionMap.get(MemberType.ROLE.getCode()), qualifier) ||
1431                            doAnyMemberRecordsMatch( roleBo.getMembers(), roleId, MemberType.ROLE.getCode(), qualifier ) ) {
1432                    return;
1433            }
1434            // Check to make sure this doesn't create a circular membership
1435            if (!checkForCircularRoleMembership(roleId, roleBo)) {
1436                throw new IllegalArgumentException("Circular roleBo reference.");
1437            }
1438            // create the new roleBo member object
1439            RoleMemberBo newRoleMember = new RoleMemberBo();
1440            newRoleMember.setRoleId(roleBo.getId());
1441            newRoleMember.setMemberId(roleId);
1442            newRoleMember.setMemberType(MemberType.ROLE);
1443            // build roleBo member attribute objects from the given Map<String, String>
1444            addMemberAttributeData(newRoleMember, qualifier, roleBo.getKimTypeId());
1445    
1446            // When members are added to roles, clients must be notified.
1447            getResponsibilityInternalService().saveRoleMember(newRoleMember);
1448        }
1449    
1450        @Override
1451        public RoleMember createRoleMember(RoleMember roleMember) throws RiceIllegalStateException {
1452            incomingParamCheck(roleMember, "roleMember");
1453    
1454            if (StringUtils.isNotBlank(roleMember.getRoleMemberId()) && getRoleMemberBo(roleMember.getRoleMemberId()) != null) {
1455                throw new RiceIllegalStateException("the roleMember to create already exists: " + roleMember);
1456            }
1457    
1458            String kimTypeId = getRoleBo(roleMember.getRoleId()).getKimTypeId();
1459            List<RoleMemberAttributeDataBo> attrBos = Collections.emptyList();
1460            attrBos = KimAttributeDataBo.createFrom(RoleMemberAttributeDataBo.class, roleMember.getAttributes(), kimTypeId);
1461    
1462            RoleMemberBo bo = RoleMemberBo.from(roleMember);
1463            bo.setAttributeDetails(attrBos);
1464            return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(bo));
1465        }
1466    
1467        @Override
1468        public RoleMember updateRoleMember(@WebParam(
1469                name = "roleMember") RoleMember roleMember) throws RiceIllegalArgumentException, RiceIllegalStateException {
1470            incomingParamCheck(roleMember, "roleMember");
1471    
1472            if (StringUtils.isBlank(roleMember.getRoleMemberId()) || getRoleMemberBo(roleMember.getRoleMemberId()) == null) {
1473                throw new RiceIllegalStateException("the roleMember to update does not exists: " + roleMember);
1474            }
1475    
1476            String kimTypeId = getRoleBo(roleMember.getRoleId()).getKimTypeId();
1477            List<RoleMemberAttributeDataBo> attrBos = Collections.emptyList();
1478            attrBos = KimAttributeDataBo.createFrom(RoleMemberAttributeDataBo.class, roleMember.getAttributes(), kimTypeId);
1479    
1480            RoleMemberBo bo = RoleMemberBo.from(roleMember);
1481            bo.setAttributeDetails(attrBos);
1482            return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(bo));
1483        }
1484    
1485        @Override
1486        public RoleResponsibilityAction createRoleResponsibilityAction(RoleResponsibilityAction roleResponsibilityAction)
1487                throws RiceIllegalArgumentException, RiceIllegalStateException {
1488            incomingParamCheck(roleResponsibilityAction, "roleResponsibilityAction");
1489    
1490    
1491            if (StringUtils.isNotBlank(roleResponsibilityAction.getId())
1492                    && getBusinessObjectService().findByPrimaryKey
1493                    (RoleResponsibilityActionBo.class, Collections.singletonMap("id", roleResponsibilityAction.getId()))  != null) {
1494                throw new RiceIllegalStateException("the roleResponsibilityAction to create already exists: " + roleResponsibilityAction);
1495            }
1496    
1497            RoleResponsibilityActionBo bo = RoleResponsibilityActionBo.from(roleResponsibilityAction);
1498            return RoleResponsibilityActionBo.to(getBusinessObjectService().save(bo));
1499        }
1500    
1501        @Override
1502        public DelegateType createDelegateType(DelegateType delegateType) throws RiceIllegalStateException {
1503            incomingParamCheck(delegateType, "delegateType");
1504    
1505            if (StringUtils.isNotBlank(delegateType.getDelegationId())
1506                    && getDelegateTypeByDelegationId(delegateType.getDelegationId()) != null) {
1507                throw new RiceIllegalStateException("the delegateType to create already exists: " + delegateType);
1508            }
1509    
1510            DelegateTypeBo bo = DelegateTypeBo.from(delegateType);
1511            return DelegateTypeBo.to(getBusinessObjectService().save(bo));
1512            // look up the role
1513            /*RoleBo role = getRoleBo(delegationType.getRoleId());
1514            DelegateTypeBo delegation = getDelegationOfType(role.getId(), delegationType.getDelegationTypeCode());
1515            // create the new role member object
1516            DelegateMemberBo newDelegationMember = new DelegateMemberBo();
1517    
1518            DelegateMemberBo origDelegationMember;
1519            if(StringUtils.isNotEmpty(delegationMemberId)){
1520                    origDelegationMember = getDelegateMemberBo(delegationMemberId);
1521            } else{
1522                    List<DelegateMemberBo> origDelegationMembers =
1523                        this.getDelegationMemberBoListByMemberAndDelegationId(memberId, delegation.getDelegationId());
1524                    origDelegationMember =
1525                            (origDelegationMembers!=null && !origDelegationMembers.isEmpty()) ? origDelegationMembers.get(0) : null;
1526            }
1527            if(origDelegationMember!=null){
1528                    newDelegationMember.setDelegationMemberId(origDelegationMember.getDelegationMemberId());
1529                    newDelegationMember.setVersionNumber(origDelegationMember.getVersionNumber());
1530            }
1531            newDelegationMember.setMemberId(memberId);
1532            newDelegationMember.setDelegationId(delegation.getDelegationId());
1533            newDelegationMember.setRoleMemberId(roleMemberId);
1534            newDelegationMember.setTypeCode(memberTypeCode);
1535                    if (activeFromDate != null) {
1536                            newDelegationMember.setActiveFromDateValue(new java.sql.Timestamp(activeFromDate.getMillis()));
1537                    }
1538                    if (activeToDate != null) {
1539                            newDelegationMember.setActiveToDateValue(new java.sql.Timestamp(activeToDate.getMillis()));
1540                    }
1541    
1542            // build role member attribute objects from the given Map<String, String>
1543            addDelegationMemberAttributeData( newDelegationMember, qualifications, role.getKimTypeId() );
1544    
1545            List<DelegateMemberBo> delegationMembers = new ArrayList<DelegateMemberBo>();
1546            delegationMembers.add(newDelegationMember);
1547            delegation.setMembers(delegationMembers);
1548    
1549            getBusinessObjectService().save(delegation);
1550            for(DelegateMemberBo delegationMember: delegation.getMembers()){
1551                    deleteNullDelegationMemberAttributeData(delegationMember.getAttributes());
1552            }*/
1553        }
1554    
1555        @Override
1556        public DelegateType updateDelegateType(DelegateType delegateType) throws RiceIllegalStateException {
1557            incomingParamCheck(delegateType, "delegateType");
1558    
1559            if (StringUtils.isBlank(delegateType.getDelegationId())
1560                    || getDelegateTypeByDelegationId(delegateType.getDelegationId()) == null) {
1561                throw new RiceIllegalStateException("the delegateType to update does not exist: " + delegateType);
1562            }
1563    
1564            DelegateTypeBo bo = DelegateTypeBo.from(delegateType);
1565            return DelegateTypeBo.to(getBusinessObjectService().save(bo));
1566        }
1567    
1568    
1569        private void removeRoleMembers(List<RoleMemberBo> members) {
1570            if(CollectionUtils.isNotEmpty(members)) {
1571                for ( RoleMemberBo rm : members ) {
1572                    getResponsibilityInternalService().removeRoleMember(rm);
1573                }
1574            }
1575        }
1576    
1577        private List<RoleMemberBo> getRoleMembersByDefaultStrategy(RoleBo role, String memberId, String memberTypeCode, Map<String, String> qualifier) {
1578            List<RoleMemberBo> rms = new ArrayList<RoleMemberBo>();
1579            role.refreshReferenceObject("members");
1580            for ( RoleMemberBo rm : role.getMembers() ) {
1581                if ( doesMemberMatch( rm, memberId, memberTypeCode, qualifier ) ) {
1582                    // if found, remove
1583                    rms.add(rm);
1584                }
1585            }
1586            return rms;
1587        }
1588    
1589        @Override
1590        public void removePrincipalFromRole(String principalId,
1591                String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1592            if (StringUtils.isBlank(principalId)) {
1593                throw new RiceIllegalArgumentException("principalId is null");
1594            }
1595    
1596            if (StringUtils.isBlank(namespaceCode)) {
1597                throw new RiceIllegalArgumentException("namespaceCode is null");
1598            }
1599    
1600            if (StringUtils.isBlank(roleName)) {
1601                throw new RiceIllegalArgumentException("roleName is null");
1602            }
1603    
1604            if (qualifier == null) {
1605                throw new RiceIllegalArgumentException("qualifier is null");
1606            }
1607    
1608            // look up the role
1609            RoleBo role = getRoleBoByName(namespaceCode, roleName);
1610            // pull all the principal members
1611            // look for an exact qualifier match
1612            List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(role, principalId, memberTypeToRoleDaoActionMap.get(MemberType.PRINCIPAL.getCode()), qualifier);
1613            if(CollectionUtils.isEmpty(rms)) {
1614                rms = getRoleMembersByDefaultStrategy(role, principalId, MemberType.PRINCIPAL.getCode(), qualifier);
1615            }
1616            removeRoleMembers(rms);
1617        }
1618    
1619        @Override
1620        public void removeGroupFromRole(String groupId,
1621                String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1622            if (StringUtils.isBlank(groupId)) {
1623                throw new RiceIllegalArgumentException("groupId is null");
1624            }
1625    
1626            if (StringUtils.isBlank(namespaceCode)) {
1627                throw new RiceIllegalArgumentException("namespaceCode is null");
1628            }
1629    
1630            if (StringUtils.isBlank(roleName)) {
1631                throw new RiceIllegalArgumentException("roleName is null");
1632            }
1633    
1634            if (qualifier == null) {
1635                throw new RiceIllegalArgumentException("qualifier is null");
1636            }
1637    
1638            // look up the roleBo
1639            RoleBo roleBo = getRoleBoByName(namespaceCode, roleName);
1640            // pull all the group roleBo members
1641            // look for an exact qualifier match
1642            List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(roleBo, groupId, memberTypeToRoleDaoActionMap.get(MemberType.GROUP.getCode()), qualifier);
1643            if(CollectionUtils.isEmpty(rms)) {
1644                rms = getRoleMembersByDefaultStrategy(roleBo, groupId, MemberType.GROUP.getCode(), qualifier);
1645            }
1646            removeRoleMembers(rms);
1647        }
1648    
1649        @Override
1650        public void removeRoleFromRole(String roleId,
1651                String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1652            incomingParamCheck(roleId, "roleId");
1653            incomingParamCheck(namespaceCode, "namespaceCode");
1654            incomingParamCheck(roleName, "roleName");
1655            incomingParamCheck(qualifier, "qualifier");
1656    
1657    
1658            // look up the role
1659            RoleBo role = getRoleBoByName(namespaceCode, roleName);
1660            // pull all the group role members
1661            // look for an exact qualifier match
1662            List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(role, roleId, memberTypeToRoleDaoActionMap.get(MemberType.ROLE.getCode()), qualifier);
1663            if(CollectionUtils.isEmpty(rms)) {
1664                rms = getRoleMembersByDefaultStrategy(role, roleId, MemberType.ROLE.getCode(), qualifier);
1665            }
1666            removeRoleMembers(rms);
1667        }
1668    
1669        @Override
1670        public void assignPermissionToRole(String permissionId, String roleId) throws RiceIllegalStateException {
1671            incomingParamCheck(permissionId, "permissionId");
1672            incomingParamCheck(roleId, "roleId");
1673    
1674            RolePermissionBo newRolePermission = new RolePermissionBo();
1675    
1676            Long nextSeq = KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S, RolePermissionBo.class);
1677    
1678            if (nextSeq == null) {
1679                LOG.error("Unable to get new role permission id from sequence " + KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S);
1680                throw new RuntimeException("Unable to get new role permission id from sequence " + KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S);
1681            }
1682    
1683            newRolePermission.setId(nextSeq.toString());
1684            newRolePermission.setRoleId(roleId);
1685            newRolePermission.setPermissionId(permissionId);
1686            newRolePermission.setActive(true);
1687    
1688            getBusinessObjectService().save(newRolePermission);
1689        }
1690    
1691        protected void addMemberAttributeData(RoleMemberBo roleMember, Map<String, String> qualifier, String kimTypeId) {
1692            List<RoleMemberAttributeDataBo> attributes = new ArrayList<RoleMemberAttributeDataBo>();
1693            for (Map.Entry<String, String> entry : qualifier.entrySet()) {
1694                RoleMemberAttributeDataBo roleMemberAttrBo = new RoleMemberAttributeDataBo();
1695                roleMemberAttrBo.setAttributeValue(entry.getValue());
1696                roleMemberAttrBo.setKimTypeId(kimTypeId);
1697                roleMemberAttrBo.setAssignedToId(roleMember.getRoleMemberId());
1698                // look up the attribute ID
1699                roleMemberAttrBo.setKimAttributeId(getKimAttributeId(entry.getKey()));
1700    
1701                Map<String, String> criteria = new HashMap<String, String>();
1702                criteria.put(KimConstants.PrimaryKeyConstants.KIM_ATTRIBUTE_ID, roleMemberAttrBo.getKimAttributeId());
1703                criteria.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMember.getRoleMemberId());
1704                List<RoleMemberAttributeDataBo> origRoleMemberAttributes =
1705                        (List<RoleMemberAttributeDataBo>) getBusinessObjectService().findMatching(RoleMemberAttributeDataBo.class, criteria);
1706                RoleMemberAttributeDataBo origRoleMemberAttribute =
1707                        (origRoleMemberAttributes != null && !origRoleMemberAttributes.isEmpty()) ? origRoleMemberAttributes.get(0) : null;
1708                if (origRoleMemberAttribute != null) {
1709                    roleMemberAttrBo.setId(origRoleMemberAttribute.getId());
1710                    roleMemberAttrBo.setVersionNumber(origRoleMemberAttribute.getVersionNumber());
1711                }
1712                attributes.add(roleMemberAttrBo);
1713            }
1714            roleMember.setAttributeDetails(attributes);
1715        }
1716    
1717        protected void addDelegationMemberAttributeData( DelegateMemberBo delegationMember, Map<String, String> qualifier, String kimTypeId ) {
1718                    List<DelegateMemberAttributeDataBo> attributes = new ArrayList<DelegateMemberAttributeDataBo>();
1719                    for (  Map.Entry<String, String> entry : qualifier.entrySet() ) {
1720                            DelegateMemberAttributeDataBo delegateMemberAttrBo = new DelegateMemberAttributeDataBo();
1721                            delegateMemberAttrBo.setAttributeValue(entry.getValue());
1722                            delegateMemberAttrBo.setKimTypeId(kimTypeId);
1723                            delegateMemberAttrBo.setAssignedToId(delegationMember.getDelegationMemberId());
1724                            // look up the attribute ID
1725                            delegateMemberAttrBo.setKimAttributeId(getKimAttributeId(entry.getKey()));
1726                    Map<String, String> criteria = new HashMap<String, String>();
1727                    criteria.put(KimConstants.PrimaryKeyConstants.KIM_ATTRIBUTE_ID, delegateMemberAttrBo.getKimAttributeId());
1728                    criteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMember.getDelegationMemberId());
1729                            List<DelegateMemberAttributeDataBo> origDelegationMemberAttributes =
1730                            (List<DelegateMemberAttributeDataBo>)getBusinessObjectService().findMatching(DelegateMemberAttributeDataBo.class, criteria);
1731                            DelegateMemberAttributeDataBo origDelegationMemberAttribute =
1732                            (origDelegationMemberAttributes!=null && !origDelegationMemberAttributes.isEmpty()) ? origDelegationMemberAttributes.get(0) : null;
1733                    if(origDelegationMemberAttribute!=null){
1734                            delegateMemberAttrBo.setId(origDelegationMemberAttribute.getId());
1735                            delegateMemberAttrBo.setVersionNumber(origDelegationMemberAttribute.getVersionNumber());
1736                    }
1737                            attributes.add( delegateMemberAttrBo );
1738                    }
1739                    delegationMember.setAttributes( attributes );
1740            }
1741    
1742    
1743    
1744        // --------------------
1745        // Persistence Methods
1746        // --------------------
1747    
1748            private void deleteNullMemberAttributeData(List<RoleMemberAttributeDataBo> attributes) {
1749                    List<RoleMemberAttributeDataBo> attributesToDelete = new ArrayList<RoleMemberAttributeDataBo>();
1750                    for(RoleMemberAttributeDataBo attribute: attributes){
1751                            if(attribute.getAttributeValue()==null){
1752                                    attributesToDelete.add(attribute);
1753                            }
1754                    }
1755                    getBusinessObjectService().delete(attributesToDelete);
1756            }
1757    
1758        private void deleteNullDelegationMemberAttributeData(List<DelegateMemberAttributeDataBo> attributes) {
1759            List<DelegateMemberAttributeDataBo> attributesToDelete = new ArrayList<DelegateMemberAttributeDataBo>();
1760    
1761                    for(DelegateMemberAttributeDataBo attribute: attributes){
1762                            if(attribute.getAttributeValue()==null){
1763                                    attributesToDelete.add(attribute);
1764                            }
1765                    }
1766                    getBusinessObjectService().delete(attributesToDelete);
1767            }
1768    
1769        private void incomingParamCheck(Object object, String name) {
1770            if (object == null) {
1771                throw new RiceIllegalArgumentException(name + " was null");
1772            } else if (object instanceof String
1773                    && StringUtils.isBlank((String) object)) {
1774                throw new RiceIllegalArgumentException(name + " was blank");
1775            }
1776        }
1777    }