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