View Javadoc

1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kim.impl.role;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.commons.lang.exception.ExceptionUtils;
21  import org.apache.log4j.Logger;
22  import org.joda.time.DateTime;
23  import org.kuali.rice.core.api.CoreConstants;
24  import org.kuali.rice.core.api.cache.CacheKeyUtils;
25  import org.kuali.rice.core.api.criteria.CriteriaLookupService;
26  import org.kuali.rice.core.api.criteria.GenericQueryResults;
27  import org.kuali.rice.core.api.criteria.LookupCustomizer;
28  import org.kuali.rice.core.api.criteria.QueryByCriteria;
29  import org.kuali.rice.core.api.delegation.DelegationType;
30  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
31  import org.kuali.rice.core.api.exception.RiceIllegalStateException;
32  import org.kuali.rice.core.api.membership.MemberType;
33  import org.kuali.rice.core.api.mo.ModelObjectUtils;
34  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
35  import org.kuali.rice.core.api.util.VersionHelper;
36  import org.kuali.rice.kim.api.KimConstants;
37  import org.kuali.rice.kim.api.common.delegate.DelegateMember;
38  import org.kuali.rice.kim.api.common.delegate.DelegateType;
39  import org.kuali.rice.kim.api.identity.principal.Principal;
40  import org.kuali.rice.kim.api.role.DelegateMemberQueryResults;
41  import org.kuali.rice.kim.api.role.Role;
42  import org.kuali.rice.kim.api.role.RoleMember;
43  import org.kuali.rice.kim.api.role.RoleMemberQueryResults;
44  import org.kuali.rice.kim.api.role.RoleMembership;
45  import org.kuali.rice.kim.api.role.RoleMembershipQueryResults;
46  import org.kuali.rice.kim.api.role.RoleQueryResults;
47  import org.kuali.rice.kim.api.role.RoleResponsibility;
48  import org.kuali.rice.kim.api.role.RoleResponsibilityAction;
49  import org.kuali.rice.kim.api.role.RoleService;
50  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
51  import org.kuali.rice.kim.api.type.KimType;
52  import org.kuali.rice.kim.api.type.KimTypeUtils;
53  import org.kuali.rice.kim.framework.common.delegate.DelegationTypeService;
54  import org.kuali.rice.kim.framework.role.RoleTypeService;
55  import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator;
56  import org.kuali.rice.kim.framework.type.KimTypeService;
57  import org.kuali.rice.kim.impl.common.attribute.AttributeTransform;
58  import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo;
59  import org.kuali.rice.kim.impl.common.delegate.DelegateMemberAttributeDataBo;
60  import org.kuali.rice.kim.impl.common.delegate.DelegateMemberBo;
61  import org.kuali.rice.kim.impl.common.delegate.DelegateTypeBo;
62  import org.kuali.rice.kim.impl.services.KimImplServiceLocator;
63  import org.kuali.rice.kim.impl.type.KimTypeBo;
64  import org.kuali.rice.krad.service.BusinessObjectService;
65  import org.kuali.rice.krad.service.KRADServiceLocator;
66  import org.kuali.rice.ksb.api.KsbApiServiceLocator;
67  import org.kuali.rice.ksb.api.bus.Endpoint;
68  import org.kuali.rice.ksb.api.bus.ServiceBus;
69  import org.springframework.cache.Cache;
70  import org.springframework.cache.CacheManager;
71  import org.springframework.cache.support.NoOpCacheManager;
72  import org.springframework.util.LinkedMultiValueMap;
73  import org.springframework.util.MultiValueMap;
74  
75  import javax.jws.WebParam;
76  import javax.xml.namespace.QName;
77  import java.sql.Timestamp;
78  import java.util.ArrayList;
79  import java.util.Collection;
80  import java.util.Collections;
81  import java.util.Date;
82  import java.util.HashMap;
83  import java.util.HashSet;
84  import java.util.List;
85  import java.util.Map;
86  import java.util.Set;
87  
88  import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
89  
90  public class RoleServiceImpl extends RoleServiceBase implements RoleService {
91      private static final Logger LOG = Logger.getLogger(RoleServiceImpl.class);
92  
93      private static final Map<String, RoleDaoAction> memberTypeToRoleDaoActionMap = populateMemberTypeToRoleDaoActionMap();
94  
95      private static Map<String, RoleDaoAction> populateMemberTypeToRoleDaoActionMap() {
96          Map<String, RoleDaoAction> map = new HashMap<String, RoleDaoAction>();
97          map.put(MemberType.GROUP.getCode(), RoleDaoAction.ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS);
98          map.put(MemberType.PRINCIPAL.getCode(), RoleDaoAction.ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS);
99          map.put(MemberType.ROLE.getCode(), RoleDaoAction.ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS);
100         return Collections.unmodifiableMap(map);
101     }
102 
103     private RoleService proxiedRoleService;
104     private CacheManager cacheManager;
105 
106     public RoleServiceImpl() {
107         this.cacheManager = new NoOpCacheManager();
108     }
109 
110     @Override
111     public Role createRole(final Role role) throws RiceIllegalArgumentException, RiceIllegalStateException {
112         incomingParamCheck(role, "role");
113 
114         if (StringUtils.isNotBlank(role.getId()) && getRole(role.getId()) != null) {
115             throw new RiceIllegalStateException("the role to create already exists: " + role);
116         }
117         RoleBo bo = RoleBo.from(role);
118         return RoleBo.to(getBusinessObjectService().save(bo));
119     }
120 
121     @Override
122     public Role updateRole(final Role role) throws RiceIllegalArgumentException, RiceIllegalStateException {
123         incomingParamCheck(role, "role");
124 
125         RoleBoLite originalRole = getRoleBoLite(role.getId());
126         if (StringUtils.isBlank(role.getId()) || originalRole == null) {
127             throw new RiceIllegalStateException("the role does not exist: " + role);
128         }
129 
130         RoleBo bo = RoleBo.from(role);
131 
132         RoleBo updatedRole = getBusinessObjectService().save(bo);
133         if (originalRole.isActive()
134                 && !updatedRole.isActive()) {
135             KimImplServiceLocator.getRoleInternalService().roleInactivated(updatedRole.getId());
136         }
137         return RoleBo.to(updatedRole);
138     }
139 
140     /**
141      * This method tests to see if assigning a roleBo to another roleBo will create a circular reference.
142      * The Role is checked to see if it is a member (direct or nested) of the roleBo to be assigned as a member.
143      *
144      * @param newMemberId
145      * @param roleBo
146      * @return true  - assignment is allowed, no circular reference will be created.
147      *         false - illegal assignment, it will create a circular membership
148      */
149     protected boolean checkForCircularRoleMembership(String newMemberId, RoleBo roleBo) {
150         // get all nested roleBo members that are of type roleBo
151         Set<String> newRoleMemberIds = getRoleTypeRoleMemberIds(newMemberId);
152         return !newRoleMemberIds.contains(roleBo.getId());
153     }
154 
155     protected RoleMember findRoleMember(String roleMemberId) {
156         final List<RoleMember> roleMembers = findRoleMembers(QueryByCriteria.Builder.fromPredicates(equal(KimConstants.PrimaryKeyConstants.ID, roleMemberId))).getResults();
157         if (roleMembers != null && !roleMembers.isEmpty()) {
158             return roleMembers.get(0);
159         }
160         return null;
161     }
162 
163     @Override
164     public RoleMemberQueryResults findRoleMembers(QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
165         incomingParamCheck(queryByCriteria, "queryByCriteria");
166 
167         //KULRICE-8972 lookup customizer for attribute transform
168         LookupCustomizer.Builder<RoleMemberBo> lc = LookupCustomizer.Builder.create();
169         lc.setPredicateTransform(AttributeTransform.getInstance());
170 
171         GenericQueryResults<RoleMemberBo> results = getCriteriaLookupService().lookup(RoleMemberBo.class, queryByCriteria, lc.build());
172 
173         RoleMemberQueryResults.Builder builder = RoleMemberQueryResults.Builder.create();
174         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
175         builder.setTotalRowCount(results.getTotalRowCount());
176 
177         final List<RoleMember.Builder> ims = new ArrayList<RoleMember.Builder>();
178         for (RoleMemberBo bo : results.getResults()) {
179             ims.add(RoleMember.Builder.create(bo));
180         }
181 
182         builder.setResults(ims);
183         return builder.build();
184 
185     }
186 
187 
188 
189     @Override
190     public Set<String> getRoleTypeRoleMemberIds(String roleId) throws RiceIllegalArgumentException  {
191         incomingParamCheck(roleId, "roleId");
192 
193         Set<String> results = new HashSet<String>();
194         getNestedRoleTypeMemberIds(roleId, results);
195         return Collections.unmodifiableSet(results);
196     }
197 
198     @Override
199     public List<String> getMemberParentRoleIds(String memberType, String memberId) throws RiceIllegalStateException  {
200         incomingParamCheck(memberType, "memberType");
201         incomingParamCheck(memberId, "memberId");
202 
203         List<RoleMemberBo> parentRoleMembers = getRoleDao().getRoleMembershipsForMemberId(memberType, memberId,
204                 Collections.<String, String>emptyMap());
205 
206         List<String> parentRoleIds = new ArrayList<String>(parentRoleMembers.size());
207         for (RoleMemberBo parentRoleMember : parentRoleMembers) {
208             parentRoleIds.add(parentRoleMember.getRoleId());
209         }
210 
211         return parentRoleIds;
212     }
213 
214     @Override
215     public List<RoleResponsibilityAction> getRoleMemberResponsibilityActions(String roleMemberId) throws RiceIllegalStateException  {
216         incomingParamCheck(roleMemberId, "roleMemberId");
217 
218         Map<String, String> criteria = new HashMap<String, String>(1);
219         criteria.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMemberId);
220 
221         List<RoleResponsibilityActionBo> responsibilityActionBoList = (List<RoleResponsibilityActionBo>)
222                 getBusinessObjectService().findMatching(RoleResponsibilityActionBo.class, criteria);
223 
224         List<RoleResponsibilityAction> roleResponsibilityActionsList = new ArrayList<RoleResponsibilityAction>();
225         for (RoleResponsibilityActionBo roleResponsibilityActionBo : responsibilityActionBoList) {
226             RoleResponsibilityAction roleResponsibility = RoleResponsibilityActionBo.to(roleResponsibilityActionBo);
227             roleResponsibilityActionsList.add(roleResponsibility);
228         }
229         return roleResponsibilityActionsList;
230     }
231 
232     @Override
233     public DelegateMemberQueryResults findDelegateMembers(QueryByCriteria queryByCriteria) throws RiceIllegalStateException  {
234         incomingParamCheck(queryByCriteria, "queryByCriteria");
235 
236         //KULRICE-8972 lookup customizer for attribute transform
237         LookupCustomizer.Builder<DelegateMemberBo> lc = LookupCustomizer.Builder.create();
238         lc.setPredicateTransform(AttributeTransform.getInstance());
239 
240         GenericQueryResults<DelegateMemberBo> results = getCriteriaLookupService().lookup(DelegateMemberBo.class, queryByCriteria, lc.build());
241 
242         DelegateMemberQueryResults.Builder builder = DelegateMemberQueryResults.Builder.create();
243         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
244         builder.setTotalRowCount(results.getTotalRowCount());
245 
246         final List<DelegateMember.Builder> ims = new ArrayList<DelegateMember.Builder>();
247         for (DelegateMemberBo bo : results.getResults()) {
248             ims.add(DelegateMember.Builder.create(bo));
249         }
250 
251         builder.setResults(ims);
252         return builder.build();
253     }
254 
255     @Override
256     public Role getRole(String roleId) throws RiceIllegalStateException  {
257         incomingParamCheck(roleId, "roleId");
258         return loadRole(roleId);
259     }
260 
261     /**
262      * Loads the role with the given id, leveraging the cache where possible and querying the database
263      * if role not already in the cache. If the role is not in the cache, then it will be placed in
264      * the cache once it is loaded.
265      */
266     protected Role loadRole(String roleId) {
267         Role role = getRoleFromCache(roleId);
268         if (role == null) {
269             RoleBoLite roleBo = getRoleBoLite(roleId);
270             if (roleBo != null) {
271                 role = RoleBoLite.to(roleBo);
272                 putRoleInCache(role);
273             }
274         }
275         return role;
276     }
277 
278     protected Role getRoleFromCache(String id) {
279         Cache cache = cacheManager.getCache(Role.Cache.NAME);
280         Cache.ValueWrapper cachedValue = cache.get("id=" + id);
281         if (cachedValue != null) {
282             return (Role)cachedValue.get();
283         }
284         return null;
285     }
286 
287     protected Role getRoleFromCache(String namespaceCode, String name) {
288         Cache cache = cacheManager.getCache(Role.Cache.NAME);
289         Cache.ValueWrapper cachedValue = cache.get("namespaceCode=" + namespaceCode + "|name=" + name);
290         if (cachedValue != null) {
291             return (Role)cachedValue.get();
292         }
293         return null;
294     }
295 
296     protected void putRoleInCache(Role role) {
297         if (role != null) {
298             Cache cache = cacheManager.getCache(Role.Cache.NAME);
299             String idKey = "id=" + role.getId();
300             String nameKey = "namespaceCode=" + role.getNamespaceCode() + "|name=" + role.getName();
301             cache.put(idKey, role);
302             cache.put(nameKey, role);
303         }
304     }
305 
306     protected Map<String, RoleBoLite> getRoleBoLiteMap(Collection<String> roleIds) {
307         Map<String, RoleBoLite> result;
308         // check for a non-null result in the cache, return it if found
309         if (roleIds.size() == 1) {
310             String roleId = roleIds.iterator().next();
311             RoleBoLite bo = getRoleBoLite(roleId);
312             if (bo == null) {
313                 return Collections.<String, RoleBoLite>emptyMap();
314             }
315             result = bo.isActive() ? Collections.singletonMap(roleId, bo) :  Collections.<String, RoleBoLite>emptyMap();
316         } else {
317             result = new HashMap<String, RoleBoLite>(roleIds.size());
318             for (String roleId : roleIds) {
319                 RoleBoLite bo = getRoleBoLite(roleId);
320                 if (bo != null && bo.isActive()) {
321                     result.put(roleId, bo);
322                 }
323             }
324         }
325         return result;
326     }
327 
328     @Override
329     public List<Role> getRoles(List<String> roleIds) throws RiceIllegalStateException  {
330         if (CollectionUtils.isEmpty(roleIds)) {
331             throw new RiceIllegalArgumentException("roleIds is null or empty");
332         }
333         return Collections.unmodifiableList(loadRoles(roleIds));
334     }
335 
336     /**
337      * Loads the roles with the given ids, leveraging the cache where possible and querying the database
338      * for role ids not already in the cache. If the role is not in the cache, then it will be placed in
339      * the cache once it is loaded.
340      */
341     protected List<Role> loadRoles(List<String> roleIds) {
342         List<String> remainingRoleIds = new ArrayList<String>();
343         Map<String, Role> roleMap = new HashMap<String, Role>(roleIds.size());
344         for (String roleId : roleIds) {
345             Role role = getRoleFromCache(roleId);
346             if (role != null) {
347                 roleMap.put(roleId, role);
348             } else {
349                 remainingRoleIds.add(roleId);
350             }
351         }
352         if (!remainingRoleIds.isEmpty()) {
353             Map<String, RoleBoLite> roleBoMap = getRoleBoLiteMap(remainingRoleIds);
354             for (String roleId : roleBoMap.keySet()) {
355                 RoleBoLite roleBo = roleBoMap.get(roleId);
356                 if (roleBo != null) {
357                     Role role = RoleBoLite.to(roleBo);
358                     roleMap.put(roleId, role);
359                     putRoleInCache(role);
360                 }
361             }
362         }
363         List<Role> roles = new ArrayList<Role>(roleMap.values());
364         return roles;
365     }
366 
367     @Override
368     public Role getRoleByNamespaceCodeAndName(String namespaceCode, String roleName) throws RiceIllegalStateException  {
369         incomingParamCheck(namespaceCode, "namespaceCode");
370         incomingParamCheck(roleName, "roleName");
371         return loadRoleByName(namespaceCode, roleName);
372     }
373 
374     /**
375      * Loads the role with the given name, leveraging the cache where possible and querying the database
376      * if role not already in the cache. If the role is not in the cache, then it will be placed in
377      * the cache once it is loaded.
378      */
379     protected Role loadRoleByName(String namespaceCode, String roleName) {
380         Role role = getRoleFromCache(namespaceCode, roleName);
381         if (role == null) {
382             RoleBoLite roleBo = getRoleBoLiteByName(namespaceCode, roleName);
383             if (roleBo != null) {
384                 role = getRoleFromCache(roleBo.getId());
385                 if (role == null) {
386                     role = RoleBoLite.to(roleBo);
387                 }
388                 putRoleInCache(role);
389             }
390         }
391         return role;
392     }
393 
394     @Override
395     public String getRoleIdByNamespaceCodeAndName(String namespaceCode, String roleName) throws RiceIllegalStateException  {
396         incomingParamCheck(namespaceCode, "namespaceCode");
397         incomingParamCheck(roleName, "roleName");
398 
399         Role role = getRoleByNamespaceCodeAndName(namespaceCode, roleName);
400         if (role != null) {
401             return role.getId();
402         } else {
403             return null;
404         }
405     }
406 
407     @Override
408     public boolean isRoleActive(String roleId) throws RiceIllegalStateException  {
409         incomingParamCheck(roleId, "roleId");
410         Role role = getRole(roleId);
411         return role != null && role.isActive();
412     }
413 
414     @Override
415     public List<Map<String, String>> getRoleQualifersForPrincipalByRoleIds(String principalId, List<String> roleIds,
416             Map<String, String> qualification) throws RiceIllegalStateException  {
417         incomingParamCheck(principalId, "principalId");
418         incomingParamCheck(roleIds, "roleIds");
419 
420         List<Map<String, String>> results = new ArrayList<Map<String, String>>();
421 
422         List<RoleMemberBo> roleMemberBoList = getStoredRoleMembersUsingExactMatchOnQualification(principalId, null,
423                 roleIds, qualification);
424 
425         Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
426         for (RoleMemberBo roleMemberBo : roleMemberBoList) {
427             // gather up the qualifier sets and the service they go with
428             if (MemberType.PRINCIPAL.equals(roleMemberBo.getType())) {
429                 RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
430                 if (roleTypeService != null) {
431                     List<RoleMembership> las = roleIdToMembershipMap.get(roleMemberBo.getRoleId());
432                     if (las == null) {
433                         las = new ArrayList<RoleMembership>();
434                         roleIdToMembershipMap.put(roleMemberBo.getRoleId(), las);
435                     }
436                     RoleMembership mi = RoleMembership.Builder.create(
437                             roleMemberBo.getRoleId(),
438                             roleMemberBo.getId(),
439                             roleMemberBo.getMemberId(),
440                             roleMemberBo.getType(),
441                             roleMemberBo.getAttributes()).build();
442 
443                     las.add(mi);
444                 } else {
445                     results.add(roleMemberBo.getAttributes());
446                 }
447             }
448         }
449         for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
450             RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
451             //it is possible that the the roleTypeService is coming from a remote application
452             // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
453             try {
454                 List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification, entry.getValue());
455                 for (RoleMembership rmi : matchingMembers) {
456                     results.add(rmi.getQualifier());
457                 }
458             } catch (Exception ex) {
459                 LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
460             }
461         }
462         return Collections.unmodifiableList(results);
463     }
464 
465     @Override
466     public List<Map<String, String>> getRoleQualifersForPrincipalByNamespaceAndRolename(String principalId,
467             String namespaceCode, String roleName, Map<String, String> qualification)
468             throws RiceIllegalStateException {
469         incomingParamCheck(principalId, "principalId");
470         incomingParamCheck(namespaceCode, "namespaceCode");
471         incomingParamCheck(roleName, "roleName");
472 
473         String roleId = getRoleIdByNamespaceCodeAndName(namespaceCode, roleName);
474         if (roleId == null) {
475             return Collections.emptyList();
476         }
477         return getNestedRoleQualifiersForPrincipalByRoleIds(principalId, Collections.singletonList(roleId),
478                 qualification);
479     }
480 
481     @Override
482     public List<Map<String, String>> getNestedRoleQualifersForPrincipalByNamespaceAndRolename(String principalId,
483             String namespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
484         incomingParamCheck(principalId, "principalId");
485         incomingParamCheck(namespaceCode, "namespaceCode");
486         incomingParamCheck(roleName, "roleName");
487 
488         String roleId = getRoleIdByNamespaceCodeAndName(namespaceCode, roleName);
489         if (roleId == null) {
490             return new ArrayList<Map<String, String>>(0);
491         }
492         return getNestedRoleQualifiersForPrincipalByRoleIds(principalId, Collections.singletonList(roleId),
493                 qualification);
494     }
495 
496     @Override
497     public List<Map<String, String>> getNestedRoleQualifiersForPrincipalByRoleIds(String principalId,
498             List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
499         incomingParamCheck(principalId, "principalId");
500         incomingParamCheck(roleIds, "roleIds");
501 
502 
503         List<Map<String, String>> results = new ArrayList<Map<String, String>>();
504 
505         Map<String, RoleBoLite> roleBosById = getRoleBoLiteMap(roleIds);
506 
507         // get the person's groups
508         List<String> groupIds = getGroupService().getGroupIdsByPrincipalId(principalId);
509         List<RoleMemberBo> roleMemberBos = getStoredRoleMembersUsingExactMatchOnQualification(principalId, groupIds, roleIds, qualification);
510 
511         Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
512         for (RoleMemberBo roleMemberBo : roleMemberBos) {
513             RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
514             // gather up the qualifier sets and the service they go with
515             if (MemberType.PRINCIPAL.equals(roleMemberBo.getType())
516                     || MemberType.GROUP.equals(roleMemberBo.getType())) {
517                 if (roleTypeService != null) {
518                     List<RoleMembership> las = roleIdToMembershipMap.get(roleMemberBo.getRoleId());
519                     if (las == null) {
520                         las = new ArrayList<RoleMembership>();
521                         roleIdToMembershipMap.put(roleMemberBo.getRoleId(), las);
522                     }
523                     RoleMembership mi = RoleMembership.Builder.create(
524                             roleMemberBo.getRoleId(),
525                             roleMemberBo.getId(),
526                             roleMemberBo.getMemberId(),
527                             roleMemberBo.getType(),
528                             roleMemberBo.getAttributes()).build();
529 
530                     las.add(mi);
531                 } else {
532                     results.add(roleMemberBo.getAttributes());
533                 }
534             } else if (MemberType.ROLE.equals(roleMemberBo.getType())) {
535                 // find out if the user has the role
536                 // need to convert qualification using this role's service
537                 Map<String, String> nestedQualification = qualification;
538                 if (roleTypeService != null) {
539                     RoleBoLite roleBo = roleBosById.get(roleMemberBo.getRoleId());
540                     // pulling from here as the nested roleBo is not necessarily (and likely is not)
541                     // in the roleBosById Map created earlier
542                     RoleBoLite nestedRole = getRoleBoLite(roleMemberBo.getMemberId());
543                     //it is possible that the the roleTypeService is coming from a remote application
544                     // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
545                     try {
546                         nestedQualification = getNestedQualification(nestedRole,
547                                 roleBo.getNamespaceCode(), roleBo.getName(), nestedRole.getNamespaceCode(),
548                                 nestedRole.getName(), qualification, roleMemberBo.getAttributes());
549                     } catch (Exception ex) {
550                         LOG.warn("Not able to retrieve RoleTypeService from remote system for roleBo Id: " + roleBo.getId(), ex);
551                     }
552                 }
553                 List<String> nestedRoleId = new ArrayList<String>(1);
554                 nestedRoleId.add(roleMemberBo.getMemberId());
555                 // if the user has the given role, add the qualifier the *nested role* has with the
556                 // originally queries role
557                 if (this.getProxiedRoleService().principalHasRole(principalId, nestedRoleId, nestedQualification, false)) {
558                     results.add(roleMemberBo.getAttributes());
559                 }
560             }
561         }
562         for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
563             RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
564             //it is possible that the the roleTypeService is coming from a remote
565             // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
566             try {
567                 List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification,
568                         entry.getValue());
569                 for (RoleMembership roleMembership : matchingMembers) {
570                     results.add(roleMembership.getQualifier());
571                 }
572             } catch (Exception ex) {
573                 LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
574             }
575         }
576         return Collections.unmodifiableList(results);
577     }
578 
579     @Override
580     public List<RoleMembership> getRoleMembers(List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
581         incomingParamCheck(roleIds, "roleIds");
582 
583         Set<String> foundRoleTypeMembers = new HashSet<String>();
584         List<RoleMembership> roleMembers = getRoleMembers(roleIds, qualification, true, foundRoleTypeMembers);
585 
586         return Collections.unmodifiableList(roleMembers);
587     }
588 
589     @Override
590     public Collection<String> getRoleMemberPrincipalIds(String namespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
591         incomingParamCheck(namespaceCode, "namespaceCode");
592         incomingParamCheck(roleName, "roleName");
593 
594         Set<String> principalIds = new HashSet<String>();
595         Set<String> foundRoleTypeMembers = new HashSet<String>();
596         List<String> roleIds = Collections.singletonList(getRoleIdByNamespaceCodeAndName(namespaceCode, roleName));
597         for (RoleMembership roleMembership : getRoleMembers(roleIds, qualification, false, foundRoleTypeMembers)) {
598             if (MemberType.GROUP.equals(roleMembership.getType())) {
599                 principalIds.addAll(getGroupService().getMemberPrincipalIds(roleMembership.getMemberId()));
600             } else {
601                 principalIds.add(roleMembership.getMemberId());
602             }
603         }
604 
605         return Collections.unmodifiableSet(principalIds);
606     }
607 
608     @Override
609     public boolean principalHasRole(String principalId, List<String> roleIds, Map<String, String> qualification) throws RiceIllegalStateException {
610 
611         if ( LOG.isDebugEnabled() ) {
612             logPrincipalHasRoleCheck(principalId, roleIds, qualification);
613         }
614 
615         boolean hasRole = this.getProxiedRoleService().principalHasRole(principalId, roleIds, qualification, true);
616 
617         if ( LOG.isDebugEnabled() ) {
618             LOG.debug( "Result: " + hasRole );
619         }
620 
621         return hasRole;
622     }
623 
624     @Override
625     public List<String> getPrincipalIdSubListWithRole(List<String> principalIds,
626             String roleNamespaceCode, String roleName, Map<String, String> qualification) throws RiceIllegalStateException {
627         incomingParamCheck(principalIds, "principalIds");
628         incomingParamCheck(roleNamespaceCode, "roleNamespaceCode");
629         incomingParamCheck(roleName, "roleName");
630 
631         List<String> subList = new ArrayList<String>();
632         RoleBoLite role = getRoleBoLiteByName(roleNamespaceCode, roleName);
633         for (String principalId : principalIds) {
634             if (this.getProxiedRoleService().principalHasRole(principalId, Collections.singletonList(role.getId()), qualification)) {
635                 subList.add(principalId);
636             }
637         }
638         return Collections.unmodifiableList(subList);
639     }
640 
641     @Override
642     public RoleQueryResults findRoles(QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
643         incomingParamCheck(queryByCriteria, "queryByCriteria");
644 
645         GenericQueryResults<RoleBoLite> results = getCriteriaLookupService().lookup(RoleBoLite.class, queryByCriteria);
646 
647         RoleQueryResults.Builder builder = RoleQueryResults.Builder.create();
648         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
649         builder.setTotalRowCount(results.getTotalRowCount());
650 
651         final List<Role.Builder> ims = new ArrayList<Role.Builder>();
652         for (RoleBoLite bo : results.getResults()) {
653             ims.add(Role.Builder.create(bo));
654         }
655 
656         builder.setResults(ims);
657         return builder.build();
658     }
659 
660     @Override
661     public List<RoleMembership> getFirstLevelRoleMembers(List<String> roleIds) throws RiceIllegalStateException {
662         incomingParamCheck(roleIds, "roleIds");
663         if (roleIds.isEmpty()) {
664             return Collections.emptyList();
665         }
666 
667         List<RoleMemberBo> roleMemberBoList = getStoredRoleMembersForRoleIds(roleIds, null, null);
668         List<RoleMembership> roleMemberships = new ArrayList<RoleMembership>();
669         for (RoleMemberBo roleMemberBo : roleMemberBoList) {
670             RoleMembership roleMembeship = RoleMembership.Builder.create(
671                     roleMemberBo.getRoleId(),
672                     roleMemberBo.getId(),
673                     roleMemberBo.getMemberId(),
674                     roleMemberBo.getType(),
675                     roleMemberBo.getAttributes()).build();
676             roleMemberships.add(roleMembeship);
677         }
678         return Collections.unmodifiableList(roleMemberships);
679     }
680 
681     @Override
682     public RoleMembershipQueryResults findRoleMemberships( QueryByCriteria queryByCriteria) throws RiceIllegalStateException {
683         incomingParamCheck(queryByCriteria, "queryByCriteria");
684 
685         //KULRICE-8972 lookup customizer for attribute transform
686         LookupCustomizer.Builder<RoleMemberBo> lc = LookupCustomizer.Builder.create();
687         lc.setPredicateTransform(AttributeTransform.getInstance());
688 
689         GenericQueryResults<RoleMemberBo> results = getCriteriaLookupService().lookup(RoleMemberBo.class, queryByCriteria, lc.build());
690 
691         RoleMembershipQueryResults.Builder builder = RoleMembershipQueryResults.Builder.create();
692         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
693         builder.setTotalRowCount(results.getTotalRowCount());
694 
695         final List<RoleMembership.Builder> ims = new ArrayList<RoleMembership.Builder>();
696         for (RoleMemberBo bo : results.getResults()) {
697             RoleMembership.Builder roleMembership = RoleMembership.Builder.create(
698                     bo.getRoleId(),
699                     bo.getId(),
700                     bo.getMemberId(),
701                     bo.getType(),
702                     bo.getAttributes());
703             ims.add(roleMembership);
704         }
705 
706         builder.setResults(ims);
707         return builder.build();
708     }
709 
710     @Override
711     public List<DelegateMember> getDelegationMembersByDelegationId(String delegationId) throws RiceIllegalStateException {
712         incomingParamCheck(delegationId, "delegationId");
713 
714         DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
715         if (delegateBo == null) {return Collections.emptyList();}
716 
717         return getDelegateMembersForDelegation(delegateBo);
718     }
719 
720     @Override
721     public DelegateMember getDelegationMemberByDelegationAndMemberId(String delegationId, String memberId) throws RiceIllegalStateException {
722         incomingParamCheck(delegationId, "delegationId");
723         incomingParamCheck(memberId, "memberId");
724 
725         DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
726         DelegateMemberBo delegationMember = getKimDelegationMemberImplByDelegationAndId(delegationId, memberId);
727 
728         return getDelegateCompleteInfo(delegateBo, delegationMember);
729     }
730 
731     @Override
732     public DelegateMember getDelegationMemberById(String delegationMemberId) throws RiceIllegalStateException {
733         incomingParamCheck(delegationMemberId, "delegationMemberId");
734 
735         DelegateMemberBo delegateMemberBo = getDelegateMemberBo(delegationMemberId);
736         if (delegateMemberBo == null) {
737             return null;
738         }
739 
740         DelegateTypeBo delegateBo = getKimDelegationImpl(delegateMemberBo.getDelegationId());
741 
742         return getDelegateCompleteInfo(delegateBo, delegateMemberBo);
743     }
744 
745     @Override
746     public List<RoleResponsibility> getRoleResponsibilities(String roleId) throws RiceIllegalStateException {
747         incomingParamCheck(roleId, "roleId");
748 
749         Map<String, String> criteria = new HashMap<String, String>(1);
750         criteria.put(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID, roleId);
751         List<RoleResponsibilityBo> roleResponsibilityBos = (List<RoleResponsibilityBo>)
752                 getBusinessObjectService().findMatching(RoleResponsibilityBo.class, criteria);
753         List<RoleResponsibility> roleResponsibilities = new ArrayList<RoleResponsibility>();
754 
755         for (RoleResponsibilityBo roleResponsibilityImpl : roleResponsibilityBos) {
756             roleResponsibilities.add(RoleResponsibilityBo.to(roleResponsibilityImpl));
757         }
758         return Collections.unmodifiableList(roleResponsibilities);
759     }
760 
761     @Override
762     public DelegateType getDelegateTypeByRoleIdAndDelegateTypeCode(String roleId, DelegationType delegationType) throws RiceIllegalStateException {
763         incomingParamCheck(roleId, "roleId");
764         incomingParamCheck(delegationType, "delegationType");
765 
766         DelegateTypeBo delegateBo = getDelegationOfType(roleId, delegationType);
767         return DelegateTypeBo.to(delegateBo);
768     }
769 
770     @Override
771     public DelegateType getDelegateTypeByDelegationId(String delegationId) throws RiceIllegalStateException {
772         incomingParamCheck(delegationId, "delegationId");
773 
774         DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
775         return DelegateTypeBo.to(delegateBo);
776     }
777 
778     protected List<RoleMembership> getRoleMembers(List<String> roleIds, Map<String, String> qualification, boolean followDelegations, Set<String> foundRoleTypeMembers) {
779         List<RoleMembership> results = new ArrayList<RoleMembership>();
780         Set<String> allRoleIds = new HashSet<String>();
781         for (String roleId : roleIds) {
782             if (this.getProxiedRoleService().isRoleActive(roleId)) {
783                 allRoleIds.add(roleId);
784             }
785         }
786         // short-circuit if no roles match
787         if (allRoleIds.isEmpty()) {
788             return Collections.emptyList();
789         }
790         Set<String> matchingRoleIds = new HashSet<String>(allRoleIds.size());
791         // for efficiency, retrieve all roles and store in a map
792         Map<String, RoleBoLite> roles = getRoleBoLiteMap(allRoleIds);
793 
794         List<String> copyRoleIds = new ArrayList<String>(allRoleIds);
795         List<RoleMemberBo> rms = new ArrayList<RoleMemberBo>();
796 
797         for (String roleId : allRoleIds) {
798             RoleTypeService roleTypeService = getRoleTypeService(roleId);
799             if (roleTypeService != null) {
800                 List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
801                 if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
802                     copyRoleIds.remove(roleId);
803                     rms.addAll(getStoredRoleMembersForRoleIds(Collections.singletonList(roleId), null, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
804                 }
805             }
806         }
807         if (CollectionUtils.isNotEmpty(copyRoleIds)) {
808             rms.addAll(getStoredRoleMembersForRoleIds(copyRoleIds, null, null));
809         }
810 
811         // build a map of role ID to membership information
812         // this will be used for later qualification checks
813         Map<String, List<RoleMembership>> roleIdToMembershipMap = new HashMap<String, List<RoleMembership>>();
814         for (RoleMemberBo roleMemberBo : rms) {
815             RoleMembership mi = RoleMembership.Builder.create(
816                     roleMemberBo.getRoleId(),
817                     roleMemberBo.getId(),
818                     roleMemberBo.getMemberId(),
819                     roleMemberBo.getType(),
820                     roleMemberBo.getAttributes()).build();
821 
822             // if the qualification check does not need to be made, just add the result
823             if ((qualification == null || qualification.isEmpty())) {
824                 if (MemberType.ROLE.equals(roleMemberBo.getType())) {
825                     // if a role member type, do a non-recursive role member check
826                     // to obtain the group and principal members of that role
827                     // given the qualification
828                     Map<String, String> nestedRoleQualification = qualification;
829                     RoleTypeService roleTypeService = getRoleTypeService(roleMemberBo.getRoleId());
830                     if (roleTypeService != null) {
831                         // get the member role object
832                         RoleBoLite memberRole = getRoleBoLite(mi.getMemberId());
833                         nestedRoleQualification = getNestedQualification(memberRole, roles.get(
834                                 roleMemberBo.getRoleId()).getNamespaceCode(), roles.get(roleMemberBo.getRoleId())
835                                 .getName(), memberRole.getNamespaceCode(), memberRole.getName(), qualification, roleMemberBo.getAttributes());
836                     }
837                     if (this.getProxiedRoleService().isRoleActive(roleMemberBo.getRoleId())) {
838                         Collection<RoleMembership> nestedRoleMembers = getNestedRoleMembers(nestedRoleQualification, mi, foundRoleTypeMembers);
839                         if (!nestedRoleMembers.isEmpty()) {
840                             results.addAll(nestedRoleMembers);
841                             matchingRoleIds.add(roleMemberBo.getRoleId());
842                         }
843                     }
844                 } else { // not a role member type
845                     results.add(mi);
846                     matchingRoleIds.add(roleMemberBo.getRoleId());
847                 }
848                 matchingRoleIds.add(roleMemberBo.getRoleId());
849             } else {
850                 List<RoleMembership> lrmi = roleIdToMembershipMap.get(mi.getRoleId());
851                 if (lrmi == null) {
852                     lrmi = new ArrayList<RoleMembership>();
853                     roleIdToMembershipMap.put(mi.getRoleId(), lrmi);
854                 }
855                 lrmi.add(mi);
856             }
857         }
858         // if there is anything in the role to membership map, we need to check the role type services
859         // for those entries
860         if (!roleIdToMembershipMap.isEmpty()) {
861             // for each role, send in all the qualifiers for that role to the type service
862             // for evaluation, the service will return those which match
863             for (Map.Entry<String, List<RoleMembership>> entry : roleIdToMembershipMap.entrySet()) {
864                 //it is possible that the the roleTypeService is coming from a remote application
865                 // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
866                 try {
867                     RoleTypeService roleTypeService = getRoleTypeService(entry.getKey());
868                     List<RoleMembership> matchingMembers = roleTypeService.getMatchingRoleMemberships(qualification,
869                             entry.getValue());
870                     // loop over the matching entries, adding them to the results
871                     for (RoleMembership roleMemberships : matchingMembers) {
872                         if (MemberType.ROLE.equals(roleMemberships.getType())) {
873                             // if a role member type, do a non-recursive role member check
874                             // to obtain the group and principal members of that role
875                             // given the qualification
876                             // get the member role object
877                             RoleBoLite memberRole = getRoleBoLite(roleMemberships.getMemberId());
878                             if (memberRole.isActive()) {
879                                 Map<String, String> nestedRoleQualification = getNestedQualification(memberRole,
880                                         roles.get(roleMemberships.getRoleId()).getNamespaceCode(), roles.get(
881                                         roleMemberships.getRoleId()).getName(), memberRole.getNamespaceCode(),
882                                         memberRole.getName(), qualification, roleMemberships.getQualifier());
883                                 Collection<RoleMembership> nestedRoleMembers = getNestedRoleMembers(nestedRoleQualification, roleMemberships, foundRoleTypeMembers);
884                                 if (!nestedRoleMembers.isEmpty()) {
885                                     results.addAll(nestedRoleMembers);
886                                     matchingRoleIds.add(roleMemberships.getRoleId());
887                                 }
888                             }
889                         } else { // not a role member
890                             results.add(roleMemberships);
891                             matchingRoleIds.add(roleMemberships.getRoleId());
892                         }
893                     }
894                 } catch (Exception ex) {
895                     LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + entry.getKey(), ex);
896                 }
897             }
898         }
899 
900         // handle derived roles
901         for ( String roleId : allRoleIds ) {
902             RoleTypeService roleTypeService = getRoleTypeService( roleId );
903             RoleBoLite role = roles.get( roleId );
904             // check if a derived role
905             try {
906                 if ( isDerivedRoleType(roleTypeService) ) {
907                     // for each derived role, get the list of principals and groups which are in that role given the qualification (per the role type service)
908                     List<RoleMembership> roleMembers = roleTypeService.getRoleMembersFromDerivedRole(role.getNamespaceCode(), role.getName(), qualification);
909                     if ( !roleMembers.isEmpty()  ) {
910                         matchingRoleIds.add( roleId );
911                     }
912                     for ( RoleMembership rm : roleMembers ) {
913                         RoleMembership.Builder builder = RoleMembership.Builder.create(rm);
914                         builder.setRoleId(roleId);
915                         builder.setId("*");
916                         results.add(builder.build());
917                     }
918                 }
919             } catch (Exception ex) {
920                 LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleId, ex);
921             }
922         }
923 
924         if ( followDelegations && !matchingRoleIds.isEmpty() ) {
925             // we have a list of RoleMembershipInfo objects
926             // need to get delegations for distinct list of roles in that list
927             Map<String, DelegateTypeBo> delegationIdToDelegationMap = getStoredDelegationImplMapFromRoleIds(matchingRoleIds);
928             if (!delegationIdToDelegationMap.isEmpty()) {
929                 List<RoleMembership.Builder> membershipsWithDelegations =
930                         applyDelegationsToRoleMembers(results, delegationIdToDelegationMap.values(), qualification);
931                 resolveDelegationMemberRoles(membershipsWithDelegations, qualification, foundRoleTypeMembers);
932                 results = ModelObjectUtils.buildImmutableCopy(membershipsWithDelegations);
933             }
934         }
935 
936         // sort the results if a single role type service can be identified for
937         // all the matching role members
938         if ( results.size() > 1 ) {
939             // if a single role: easy case
940             if ( matchingRoleIds.size() == 1 ) {
941                 String roleId = matchingRoleIds.iterator().next();
942                 RoleTypeService roleTypeService = getRoleTypeService( roleId );
943                 //it is possible that the the roleTypeService is coming from a remote application
944                 // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
945                 try {
946                     if ( roleTypeService != null ) {
947                         results = roleTypeService.sortRoleMembers( results );
948                     }
949                 } catch (Exception ex) {
950                     LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleId, ex);
951                 }
952             } else if ( matchingRoleIds.size() > 1 ) {
953                 // if more than one, check if there is only a single role type service
954                 String prevServiceName = null;
955                 boolean multipleServices = false;
956                 for ( String roleId : matchingRoleIds ) {
957                     String serviceName = KimApiServiceLocator.getKimTypeInfoService().getKimType(getRole(roleId).getKimTypeId()).getServiceName();
958                     if ( prevServiceName != null && !StringUtils.equals( prevServiceName, serviceName ) ) {
959                         multipleServices = true;
960                         break;
961                     }
962                     prevServiceName = serviceName;
963                 }
964                 if ( !multipleServices ) {
965                     String roleId = matchingRoleIds.iterator().next();
966                     //it is possible that the the roleTypeService is coming from a remote application
967                     // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
968                     try {
969                         RoleTypeService kimRoleTypeService = getRoleTypeService( roleId );
970                         if ( kimRoleTypeService != null ) {
971                             results = kimRoleTypeService.sortRoleMembers( results );
972                         }
973                     } catch (Exception ex) {
974                         LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleId, ex);
975                     }
976                 } else {
977                     LOG.warn( "Did not sort role members - multiple role type services found.  Role Ids: " + matchingRoleIds );
978                 }
979             }
980         }
981         return Collections.unmodifiableList(results);
982     }
983 
984     /**
985      * Checks each of the result records to determine if there are potentially applicable delegation members for that
986      * role membership.  If there are, applicable delegations and members will be linked to the RoleMemberships in the
987      * given list.  An updated list will be returned from this method which includes the appropriate linked delegations.
988      */
989     protected List<RoleMembership.Builder> applyDelegationsToRoleMembers(List<RoleMembership> roleMemberships,
990             Collection<DelegateTypeBo> delegations, Map<String, String> qualification) {
991         MultiValueMap<String, String> roleIdToRoleMembershipIds = new LinkedMultiValueMap<String, String>();
992         Map<String, RoleMembership.Builder> roleMembershipIdToBuilder = new HashMap<String, RoleMembership.Builder>();
993         List<RoleMembership.Builder> roleMembershipBuilders = new ArrayList<RoleMembership.Builder>();
994         // to make our algorithm less painful, let's do some indexing and load the given list of RoleMemberships into
995         // builders
996         for (RoleMembership roleMembership : roleMemberships) {
997             roleIdToRoleMembershipIds.add(roleMembership.getRoleId(), roleMembership.getId());
998             RoleMembership.Builder builder = RoleMembership.Builder.create(roleMembership);
999             roleMembershipBuilders.add(builder);
1000             roleMembershipIdToBuilder.put(roleMembership.getId(), builder);
1001         }
1002         for (DelegateTypeBo delegation : delegations) {
1003             // determine the candidate role memberships where this delegation can be mapped
1004             List<String> candidateRoleMembershipIds = roleIdToRoleMembershipIds.get(delegation.getRoleId());
1005             if (CollectionUtils.isNotEmpty(candidateRoleMembershipIds)) {
1006                 DelegationTypeService delegationTypeService = getDelegationTypeService(delegation.getDelegationId());
1007                 for (DelegateMemberBo delegationMember : delegation.getMembers()) {
1008                     // Make sure that the delegation member is active
1009                     if (delegationMember.isActive(DateTime.now()) && (delegationTypeService == null ||
1010                             delegationTypeService.doesDelegationQualifierMatchQualification(qualification, delegationMember.getQualifier()))) {
1011                         DelegateMember.Builder delegateMemberBuilder = DelegateMember.Builder.create(delegationMember);
1012                         // if the member has no role member id, check qualifications and apply to all matching role memberships on the role
1013                         if (StringUtils.isBlank(delegationMember.getRoleMemberId())) {
1014                             RoleTypeService roleTypeService = getRoleTypeService(delegation.getRoleId());
1015                             for (String roleMembershipId : candidateRoleMembershipIds) {
1016                                 RoleMembership.Builder roleMembershipBuilder = roleMembershipIdToBuilder.get(roleMembershipId);
1017                                 if (roleTypeService == null || roleTypeService.doesRoleQualifierMatchQualification(roleMembershipBuilder.getQualifier(), delegationMember.getQualifier())) {
1018                                     linkDelegateToRoleMembership(delegation, delegateMemberBuilder, roleMembershipBuilder);
1019                                 }
1020                             }
1021                         } else if (candidateRoleMembershipIds.contains(delegationMember.getRoleMemberId())) {
1022                             RoleMembership.Builder roleMembershipBuilder = roleMembershipIdToBuilder.get(delegationMember.getRoleMemberId());
1023                             linkDelegateToRoleMembership(delegation, delegateMemberBuilder, roleMembershipBuilder);
1024                         }
1025                     }
1026                 }
1027             }
1028         }
1029         return roleMembershipBuilders;
1030     }
1031 
1032     protected void linkDelegateToRoleMembership(DelegateTypeBo delegation, DelegateMember.Builder delegateMemberBuilder,
1033             RoleMembership.Builder roleMembershipBuilder) {
1034         DelegateType.Builder delegateBuilder = null;
1035         for(DelegateType.Builder existingDelegateBuilder : roleMembershipBuilder.getDelegates()) {
1036             if (existingDelegateBuilder.getDelegationId().equals(delegation.getDelegationId())) {
1037                 delegateBuilder = existingDelegateBuilder;
1038             }
1039         }
1040         if (delegateBuilder == null) {
1041             delegateBuilder = DelegateType.Builder.create(delegation);
1042             delegateBuilder.setMembers(new ArrayList<DelegateMember.Builder>());
1043             roleMembershipBuilder.getDelegates().add(delegateBuilder);
1044         }
1045         delegateBuilder.getMembers().add(delegateMemberBuilder);
1046 
1047     }
1048 
1049     /**
1050      * Once the delegations for a RoleMembershipInfo object have been determined,
1051      * any "role" member types need to be resolved into groups and principals so that
1052      * further KIM requests are not needed.
1053      */
1054     protected void resolveDelegationMemberRoles(List<RoleMembership.Builder> membershipBuilders,
1055             Map<String, String> qualification, Set<String> foundRoleTypeMembers) {
1056         // check delegations assigned to this role
1057         for (RoleMembership.Builder roleMembership : membershipBuilders) {
1058             // the applicable delegation IDs will already be set in the RoleMembership.Builder
1059             // this code examines those delegations and obtains the member groups and principals
1060             for (DelegateType.Builder delegation : roleMembership.getDelegates()) {
1061                 List<DelegateMember.Builder> newMembers = new ArrayList<DelegateMember.Builder>();
1062                 for (DelegateMember.Builder member : delegation.getMembers()) {
1063                     if (MemberType.ROLE.equals(member.getType())) {
1064                         // loop over delegation roles and extract the role IDs where the qualifications match
1065                         Collection<RoleMembership> delegateMembers = getRoleMembers(Collections.singletonList(
1066                                 member.getMemberId()), qualification, false, foundRoleTypeMembers);
1067                         // loop over the role members and create the needed DelegationMember builders
1068                         for (RoleMembership rmi : delegateMembers) {
1069                             DelegateMember.Builder delegateMember = DelegateMember.Builder.create(member);
1070                             delegateMember.setMemberId(rmi.getMemberId());
1071                             delegateMember.setType(rmi.getType());
1072                             newMembers.add(delegateMember);
1073                         }
1074                     } else {
1075                         newMembers.add(member);
1076                     }
1077                 }
1078                 delegation.setMembers(newMembers);
1079             }
1080         }
1081     }
1082 
1083     @Override
1084     public boolean principalHasRole(String principalId, List<String> roleIds, Map<String, String> qualification, boolean checkDelegations) {
1085 
1086         incomingParamCheck(principalId, "principalId");
1087         incomingParamCheck(roleIds, "roleIds");
1088         return principalHasRole(new Context(principalId), principalId, roleIds, qualification, checkDelegations);
1089     }
1090 
1091     /**
1092      * An internal helper class which is used to keep context for an invocation of principalHasRole.
1093      */
1094     private final class Context {
1095 
1096         private String principalId;
1097         private List<String> principalGroupIds;
1098         private Map<String, RoleTypeService> roleTypeServiceCache;
1099         private Map<String, Boolean> isDerivedRoleTypeCache;
1100 
1101         Context(String principalId) {
1102             this.principalId = principalId;
1103             this.roleTypeServiceCache = new HashMap<String, RoleTypeService>();
1104             this.isDerivedRoleTypeCache = new HashMap<String, Boolean>();
1105         }
1106 
1107         String getPrincipalId() {
1108             return principalId;
1109         }
1110 
1111         List<String> getPrincipalGroupIds() {
1112             if (principalGroupIds == null) {
1113                 principalGroupIds = getGroupService().getGroupIdsByPrincipalId(principalId);
1114             }
1115             return principalGroupIds;
1116         }
1117 
1118         RoleTypeService getRoleTypeService(String kimTypeId) {
1119             if (roleTypeServiceCache.containsKey(kimTypeId)) {
1120                 return roleTypeServiceCache.get(kimTypeId);
1121             }
1122             RoleTypeService roleTypeService = null;
1123             if (kimTypeId != null) {
1124                 KimType roleType = KimApiServiceLocator.getKimTypeInfoService().getKimType(kimTypeId);
1125                 if (roleType != null && StringUtils.isNotBlank(roleType.getServiceName())) {
1126                     roleTypeService = getRoleTypeServiceByName(roleType.getServiceName());
1127                 }
1128             }
1129             if (roleTypeService == null) {
1130                 roleTypeService = KimImplServiceLocator.getDefaultRoleTypeService();
1131             }
1132             roleTypeServiceCache.put(kimTypeId, roleTypeService);
1133             return roleTypeService;
1134         }
1135 
1136         boolean isDerivedRoleType(String kimTypeId) {
1137             Boolean isDerived = isDerivedRoleTypeCache.get(kimTypeId);
1138             if (isDerived == null) {
1139                 isDerived = Boolean.valueOf(RoleServiceImpl.this.isDerivedRoleType(getRoleTypeService(kimTypeId)));
1140                 isDerivedRoleTypeCache.put(kimTypeId, isDerived);
1141             }
1142             return isDerived.booleanValue();
1143         }
1144 
1145     }
1146 
1147 
1148     protected boolean principalHasRole(Context context, String principalId, List<String> roleIds, Map<String, String> qualification, boolean checkDelegations) {
1149 
1150         /**
1151          * This method uses a multi-phase approach to determining if the given principal of any of the roles given based
1152          * on the qualification map that is pased.
1153          *
1154          * Phase 1: Check the cache to find if it's already been determined that the principal is a member of any of
1155          *          the roles with the given ids.
1156          * Phase 2: Perform exact database-level matching. This can be done for all roles if the given qualification map
1157          *          is null or empty since that means qualification matching does not need to be performed. It can also
1158          *          be done for roles who's RoleTypeService defines qualifiers for exact match.
1159          * Phase 3: Use RoleTypeService matching for roles which have not already been checked. Will need to determine
1160          *          which role memberships match the given principal then delegate to the appropriate RoleTypeService
1161          *          to execute matching logic.
1162          * Phase 4: Check nested roles.
1163          * Phase 5: For any cases where derived roles are used, determine if the principal is a member of those
1164          *          derived roles.
1165          * Phase 6: If checkDelegations is true, check if any delegations match
1166          */
1167         try {
1168             // Phase 1: first check if any of the role membership is cached, only proceed with checking the role ids that
1169             // aren't already cached
1170 
1171             List<String> roleIdsToCheck = new ArrayList<String>(roleIds.size());
1172             for (String roleId : roleIds) {
1173                 Boolean hasRole = getPrincipalHasRoleFromCache(principalId, roleId, qualification, checkDelegations);
1174                 if (hasRole != null) {
1175                     if (hasRole.booleanValue()) {
1176                         return true;
1177                     }
1178                 } else {
1179                     roleIdsToCheck.add(roleId);
1180                 }
1181             }
1182 
1183             // load the roles, this will also filter out inactive roles!
1184             List<Role> roles = loadRoles(roleIdsToCheck);
1185             // short-circuit if no roles match
1186             if (roles.isEmpty()) {
1187                 return false;
1188             }
1189 
1190             // Phase 2: If they didn't pass any qualifications or they are using exact qualifier matching, we can go
1191             // straight to the database
1192 
1193             Set<String> rolesCheckedForExactMatch = new HashSet<String>();
1194             for (Role role : roles) {
1195                 Map<String, String> qualificationForExactMatch = null;
1196                 if (qualification == null || qualification.isEmpty()) {
1197                     qualificationForExactMatch = new HashMap<String, String>();
1198                 } else {
1199                     RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1200                     if (roleTypeService != null) {
1201                         List<String> attributesForExactMatch = getQualifiersForExactMatch(role.getKimTypeId(), roleTypeService);
1202                         if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
1203                             qualificationForExactMatch = populateQualifiersForExactMatch(qualification, attributesForExactMatch);
1204                             if (qualificationForExactMatch.isEmpty()) {
1205                                 // None of the attributes passed into principalHasRole matched attribute qualifiers on
1206                                 // the roleTypeService.  In this case we want to skip the remaining processing and
1207                                 // go onto the next role.
1208                                 continue;
1209                             }
1210                         }
1211                     }
1212                 }
1213                 if (qualificationForExactMatch != null) {
1214                     rolesCheckedForExactMatch.add(role.getId());
1215                     List<RoleMemberBo> matchingRoleMembers = getStoredRolePrincipalsForPrincipalIdAndRoleIds(
1216                             Collections.singletonList(role.getId()), principalId, qualificationForExactMatch);
1217                     // if a role member matched our principal, we're good to go
1218                     if (CollectionUtils.isNotEmpty(matchingRoleMembers)) {
1219                         return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1220                     }
1221                     // now check groups
1222                     if (!context.getPrincipalGroupIds().isEmpty()) {
1223                         List<RoleMemberBo> matchingRoleGroupMembers =
1224                                 getStoredRoleGroupsUsingExactMatchOnQualification(context.getPrincipalGroupIds(), role.getId(), qualification);
1225                         if (CollectionUtils.isNotEmpty(matchingRoleGroupMembers)) {
1226                             return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1227                         }
1228                     }
1229                     // if we drop to this point, either we didn't match or the role has nested or derived role membership,
1230                     // we'll check that later
1231                 }
1232             }
1233 
1234             // Phase 3: If we couldn't do an exact match, we need to work with the RoleTypeService in order to
1235             // perform matching
1236 
1237             for (Role role : roles) {
1238                 // if we didn't do an exact match, we need to do a manual match
1239                 if (!rolesCheckedForExactMatch.contains(role.getId())) {
1240                     List<RoleMemberBo> matchingPrincipalRoleMembers = getRoleMembersForPrincipalId(role.getId(), principalId);
1241                     List<RoleMemberBo> matchingGroupRoleMembers = getRoleMembersForGroupIds(role.getId(), context.getPrincipalGroupIds());
1242                     List<RoleMembership> roleMemberships = convertToRoleMemberships(matchingPrincipalRoleMembers, matchingGroupRoleMembers);
1243                     for (RoleMembership roleMembership : roleMemberships) {
1244                         try {
1245                             RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1246                             if (!roleTypeService.getMatchingRoleMemberships(qualification, roleMemberships).isEmpty()) {
1247                                 return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1248                             }
1249                         } catch (Exception ex) {
1250                             LOG.warn("Unable to find role type service with id: " + role.getKimTypeId());
1251                         }
1252                     }
1253                 }
1254             }
1255 
1256             // Phase 4: If we have nested roles, execute a recursive check on those
1257 
1258             // first, check that the qualifiers on the role membership match
1259             // then, perform a principalHasRole on the embedded role
1260             Map<String, Role> roleIndex = new HashMap<String, Role>();
1261             for (Role role :roles) {
1262                 roleIndex.put(role.getId(), role);
1263             }
1264             List<RoleMemberBo> roleMemberBos = getStoredRoleMembersForRoleIds(new ArrayList<String>(roleIndex.keySet()),
1265                     MemberType.ROLE.getCode(), null);
1266             for (RoleMemberBo roleMemberBo : roleMemberBos) {
1267                 Role role = roleIndex.get(roleMemberBo.getRoleId());
1268                 RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1269                 if (roleTypeService != null) {
1270                     //it is possible that the the roleTypeService is coming from a remote application
1271                     // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1272                     try {
1273                         if (roleTypeService.doesRoleQualifierMatchQualification(qualification,
1274                                 roleMemberBo.getAttributes())) {
1275                             RoleBoLite memberRole = getRoleBoLite(roleMemberBo.getMemberId());
1276                             Map<String, String> nestedRoleQualification =
1277                                     getNestedQualification(memberRole, role.getNamespaceCode(),
1278                                             role.getName(), memberRole.getNamespaceCode(), memberRole.getName(),
1279                                             qualification, roleMemberBo.getAttributes());
1280                             if (principalHasRole(context, principalId,
1281                                     Collections.singletonList(roleMemberBo.getMemberId()), nestedRoleQualification, true)) {
1282                                 return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1283                             }
1284                         }
1285                     } catch (Exception ex) {
1286                         LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleMemberBo
1287                                 .getRoleId(), ex);
1288                     }
1289                 } else {
1290                     // no qualifiers - role is always used - check membership
1291                     // no role type service, so can't convert qualification - just pass as is
1292                     if (principalHasRole(context, principalId, Collections.singletonList(roleMemberBo.getMemberId()),
1293                             qualification, true)) {
1294                         return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1295                     }
1296                 }
1297 
1298             }
1299 
1300             // Phase 5: derived roles
1301 
1302             // check for derived roles and extract principals and groups from that - then check them against the
1303             // role type service passing in the qualification and principal - the qualifier comes from the
1304             // external system (application)
1305             for (Role role : roles) {
1306                 // check if an derived role
1307                 //it is possible that the the roleTypeService is coming from a remote application
1308                 // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1309                 try {
1310                     boolean isDerivedRoleType = context.isDerivedRoleType(role.getKimTypeId());
1311                     if (isDerivedRoleType) {
1312                         RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1313                         if (roleTypeService.hasDerivedRole(principalId,
1314                                 context.getPrincipalGroupIds(), role.getNamespaceCode(), role.getName(), qualification)) {
1315                             if (!roleTypeService.dynamicRoleMembership(role.getNamespaceCode(), role.getName())) {
1316                                 putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
1317                             }
1318                             return true;
1319                         }
1320                     } else {
1321                         if(!checkDelegations) {
1322                             putPrincipalHasRoleInCache(false, principalId, role.getId(), qualification, checkDelegations);
1323                         }
1324                     }
1325                 } catch (Exception ex) {
1326                     LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + role.getId(), ex);
1327                 }
1328             }
1329 
1330             // Phase 6: delegations
1331 
1332             if (checkDelegations) {
1333                 if (matchesOnDelegation(roleIndex.keySet(), principalId, context.getPrincipalGroupIds(), qualification, context)) {
1334                     return true;
1335                 }
1336             }
1337         } catch (Exception e) {
1338             LOG.warn("Caught exception during a principalHasRole check", e);
1339         }
1340         return false;
1341     }
1342 
1343     protected Boolean getPrincipalHasRoleFromCache(String principalId, String roleId, Map<String, String> qualification, boolean checkDelegations) {
1344         String key = buildPrincipalHasRoleCacheKey(principalId, roleId, qualification, checkDelegations);
1345         Cache.ValueWrapper value = cacheManager.getCache(Role.Cache.NAME).get(key);
1346         return value == null ? null : (Boolean)value.get();
1347     }
1348 
1349     protected boolean putPrincipalHasRoleInCache(boolean principalHasRole, String principalId, String roleId,
1350             Map<String, String> qualification, boolean checkDelegations) {
1351         String key = buildPrincipalHasRoleCacheKey(principalId, roleId, qualification, checkDelegations);
1352         cacheManager.getCache(Role.Cache.NAME).put(key, Boolean.valueOf(principalHasRole));
1353         return principalHasRole;
1354     }
1355 
1356     private String buildPrincipalHasRoleCacheKey(String principalId, String roleId, Map<String, String> qualification, boolean checkDelegations) {
1357         return new StringBuilder("{principalHasRole}")
1358                 .append("principalId=").append(principalId).append("|")
1359                 .append("roleId=").append(roleId).append("|")
1360                 .append("qualification=").append(CacheKeyUtils.mapKey(qualification)).append("|")
1361                 .append("checkDelegations=").append(checkDelegations).toString();
1362     }
1363 
1364     protected List<String> getQualifiersForExactMatch(String kimTypeId, RoleTypeService roleTypeService) {
1365         String cacheKey = "{getQualifiersForExactMatch}kimTypeId=" + kimTypeId;
1366         Cache cache = cacheManager.getCache(Role.Cache.NAME);
1367         Cache.ValueWrapper value = cache.get(cacheKey);
1368         List<String> qualifiers = new ArrayList<String>();
1369         if (value == null) {
1370             try {
1371                 qualifiers = roleTypeService.getQualifiersForExactMatch();
1372                 cache.put(cacheKey, qualifiers);
1373             } catch (Exception e) {
1374                 LOG.warn("Caught exception when attempting to invoke a role type service", e);
1375             }
1376         } else {
1377             qualifiers = (List<String>)value.get();
1378         }
1379         return qualifiers;
1380     }
1381 
1382     public boolean isDerivedRoleType(RoleTypeService service) {
1383         return service != null && service.isDerivedRoleType();
1384     }
1385 
1386     private boolean dynamicRoleMembership(RoleTypeService service, Role role) {
1387         return service != null && service.dynamicRoleMembership(role.getNamespaceCode(), role.getName());
1388     }
1389 
1390     @Override
1391     public boolean isDerivedRole(String roleId) {
1392         incomingParamCheck(roleId, "roleId");
1393         RoleTypeService service = getRoleTypeService(roleId);
1394         return isDerivedRoleType(service);
1395     }
1396 
1397     @Override
1398     public boolean isDynamicRoleMembership(String roleId) {
1399         incomingParamCheck(roleId, "roleId");
1400         RoleTypeService service = getRoleTypeService(roleId);
1401         try {
1402             return dynamicRoleMembership(service, getRole(roleId));
1403         } catch (Exception e) {
1404             LOG.warn("Caught exception while invoking a role type service for role " + roleId, e);
1405             // Returning true so the role won't be cached
1406             return true;
1407         }
1408     }
1409 
1410     /**
1411      * Support method for principalHasRole.  Checks delegations on the passed in roles for the given principal and groups.  (It's assumed that the principal
1412      * belongs to the given groups.)
1413      * <p/>
1414      * Delegation checks are mostly the same as role checks except that the delegateBo itself is qualified against the original role (like a RolePrincipal
1415      * or RoleGroup.)  And then, the members of that delegateBo may have additional qualifiers which are not part of the original role qualifiers.
1416      * <p/>
1417      * For example:
1418      * <p/>
1419      * 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
1420      * 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
1421      * when it is attached to the role.
1422      * <p/>
1423      * The principals then attached to that delegateBo (which is specific to the organization), may have additional qualifiers.
1424      * For Example: dollar amount range, effective dates, document types.
1425      * As a subsequent step, those qualifiers are checked against the qualification passed in from the client.
1426      */
1427     protected boolean matchesOnDelegation(Set<String> allRoleIds, String principalId, List<String> principalGroupIds, Map<String, String> qualification, Context context) {
1428         // get the list of delegations for the roles
1429         Map<String, DelegateTypeBo> delegations = getStoredDelegationImplMapFromRoleIds(allRoleIds);
1430 
1431         // If there are no delegations then we should cache that the principal
1432         // doesn't have the given roles if those roles do not have dynamic
1433         // membership
1434         if(delegations.isEmpty()) {
1435             for(String roleId : allRoleIds) {
1436                 Role role = loadRole(roleId);
1437                 RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1438                 if(!context.isDerivedRoleType(role.getKimTypeId()) || roleTypeService == null || !roleTypeService.dynamicRoleMembership(role.getNamespaceCode(), role.getName())) {
1439                     putPrincipalHasRoleInCache(false, principalId, roleId, qualification, true);
1440                 }
1441             }
1442             return false;
1443         }
1444 
1445         // Build a map from a role ID to the delegations for that role ID
1446         Map<String, List<DelegateTypeBo>> roleToDelegations = new HashMap<String, List<DelegateTypeBo>>();
1447         for(DelegateTypeBo delegation : delegations.values()) {
1448             List<DelegateTypeBo> roleDelegations = roleToDelegations.get(delegation.getRoleId());
1449             if(roleDelegations == null) {
1450                 roleDelegations = new ArrayList<DelegateTypeBo>();
1451                 roleToDelegations.put(delegation.getRoleId(), roleDelegations);
1452             }
1453             roleDelegations.add(delegation);
1454         }
1455         // Iterate through each role and check its delegations to determine if
1456         // the principal has one of the roles
1457         for(String roleId : roleToDelegations.keySet()) {
1458             boolean matchesOnRoleDelegation = false;
1459             Role role = getRole(roleId);
1460             RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
1461             // Iterate through each delegation for this role and determine if
1462             // the principal has the role through this delegation
1463             for(DelegateTypeBo delegation : roleToDelegations.get(roleId)) {
1464                 // If the delegation isn't active skip it
1465                 if (!delegation.isActive()) {
1466                     continue;
1467                 }
1468                 // Now iterate through all of the members of the delegation to
1469                 // determine if any of them apply to this principal
1470                 for (DelegateMemberBo delegateMemberBo : delegation.getMembers()) {
1471                     // If the membership isn't active skip the rest of the checks
1472                     if (!delegateMemberBo.isActive(new Timestamp(new Date().getTime()))) {
1473                         continue;
1474                     }
1475                     // If the membership is a principal type then check the
1476                     // delegate's member ID against the principal ID
1477                     if (MemberType.PRINCIPAL.equals(delegateMemberBo.getType())
1478                             && !delegateMemberBo.getMemberId().equals(principalId)) {
1479                         continue; // no match on principal
1480                     }
1481                     // If the membership is a group type then check to see if
1482                     // the group's ID is contained in the list of groups the
1483                     // principal belongs to
1484                     if (MemberType.GROUP.equals(delegateMemberBo.getType())
1485                             && !principalGroupIds.contains(delegateMemberBo.getMemberId())) {
1486                         continue; // No match on group
1487                     }
1488                     // If the membership is a role type then we need to recurse
1489                     // into the principalHasRole method to check if this
1490                     // principal is a member of that role
1491                     if (MemberType.ROLE.equals(delegateMemberBo.getType())
1492                             && !principalHasRole(principalId, Collections.singletonList(delegateMemberBo.getMemberId()), qualification, false)) {
1493                         continue; // No match on role
1494                     }
1495 
1496                     // OK, the member matches the current user, now check the qualifications
1497 
1498                     // NOTE: this compare is slightly different than the member enumeration
1499                     // since the requested qualifier is always being used rather than
1500                     // the role qualifier for the member (which is not available)
1501 
1502                     //it is possible that the the roleTypeService is coming from a remote application
1503                     // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1504                     try {
1505                         if (roleTypeService != null && !roleTypeService.doesRoleQualifierMatchQualification(qualification, delegateMemberBo.getQualifier())) {
1506                             continue; // no match - skip to next record
1507                         }
1508                     } catch (Exception ex) {
1509                         LOG.warn("Unable to call doesRoleQualifierMatchQualification on role type service for role Id: " + delegation.getRoleId() + " / " + qualification + " / " + delegateMemberBo.getQualifier(), ex);
1510                         continue;
1511                     }
1512 
1513                     // role service matches this qualifier
1514                     // now try the delegateBo service
1515                     DelegationTypeService delegationTypeService = getDelegationTypeService(delegateMemberBo.getDelegationId());
1516                     // QUESTION: does the qualifier map need to be merged with the main delegateBo qualification?
1517                     if (delegationTypeService != null && !delegationTypeService.doesDelegationQualifierMatchQualification(qualification, delegateMemberBo.getQualifier())) {
1518                         continue; // no match - skip to next record
1519                     }
1520                     // check if a role member ID is present on the delegateBo record
1521                     // if so, check that the original role member would match the given qualifiers
1522                     if (StringUtils.isNotBlank(delegateMemberBo.getRoleMemberId())) {
1523                         RoleMemberBo rm = getRoleMemberBo(delegateMemberBo.getRoleMemberId());
1524                         if (rm != null) {
1525                             // check that the original role member's is active and that their
1526                             // qualifier would have matched this request's
1527                             // qualifications (that the original person would have the permission/responsibility
1528                             // for an action)
1529                             // this prevents a role-membership based delegateBo from surviving the inactivation/
1530                             // changing of the main person's role membership
1531                             if (!rm.isActive(new Timestamp(new Date().getTime()))) {
1532                                 continue;
1533                             }
1534                             Map<String, String> roleQualifier = rm.getAttributes();
1535                             //it is possible that the the roleTypeService is coming from a remote application
1536                             // and therefore it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
1537                             try {
1538                                 if (roleTypeService != null && !roleTypeService.doesRoleQualifierMatchQualification(qualification, roleQualifier)) {
1539                                     continue;
1540                                 }
1541                             } catch (Exception ex) {
1542                                 LOG.warn("Unable to call doesRoleQualifierMatchQualification on role type service for role Id: " + delegation.getRoleId() + " / " + qualification + " / " + roleQualifier, ex);
1543                                 continue;
1544                             }
1545                         } else {
1546                             LOG.warn("Unknown role member ID cited in the delegateBo member table:");
1547                             LOG.warn("       assignedToId: " + delegateMemberBo.getDelegationMemberId() + " / roleMemberId: " + delegateMemberBo.getRoleMemberId());
1548                         }
1549                     }
1550                     // If we've made it here then all of the tests pass so the
1551                     // principal must belong to this delegation so set the flag
1552                     // to true and break out of this loop
1553                     matchesOnRoleDelegation = true;
1554                     break;
1555                 }
1556 
1557                 // If we've found a match for one of the delegations break out
1558                 // of this loop
1559                 if(matchesOnRoleDelegation) {
1560                     break;
1561                 }
1562             }
1563             // If the role is not derived nor dynamic then cache the result of
1564             // this since the principal has the role through one of these
1565             // delegations
1566             if(!context.isDerivedRoleType(role.getKimTypeId()) || roleTypeService == null || !roleTypeService.dynamicRoleMembership(role.getNamespaceCode(), role.getName())) {
1567                 putPrincipalHasRoleInCache(matchesOnRoleDelegation, principalId, roleId, qualification, true);
1568             }
1569             // If we've found a matching delegation skip processing the rest of
1570             // the roles
1571             if(matchesOnRoleDelegation) {
1572                 return matchesOnRoleDelegation;
1573             }
1574         }
1575         // If we get here we didn't find a matching delegation so return false
1576         return false;
1577     }
1578 
1579     protected List<RoleMembership> convertToRoleMemberships(List<RoleMemberBo>... roleMemberLists) {
1580         List<RoleMembership> roleMemberships = new ArrayList<RoleMembership>();
1581         for (List<RoleMemberBo> roleMembers : roleMemberLists) {
1582             for (RoleMemberBo roleMember : roleMembers) {
1583                 RoleMembership roleMembership = RoleMembership.Builder.create(
1584                         roleMember.getRoleId(),
1585                         roleMember.getId(),
1586                         roleMember.getMemberId(),
1587                         roleMember.getType(),
1588                         roleMember.getAttributes()).build();
1589                 roleMemberships.add(roleMembership);
1590             }
1591         }
1592         return roleMemberships;
1593     }
1594 
1595     /**
1596      * Helper method used by principalHasRole to build the role ID -> list of members map.
1597      *
1598      * @return <b>true</b> if no further checks are needed because no role service is defined
1599      */
1600     protected boolean getRoleIdToMembershipMap(Map<String, List<RoleMembership>> roleIdToMembershipMap, List<RoleMemberBo> roleMembers) {
1601         for (RoleMemberBo roleMemberBo : roleMembers) {
1602             RoleMembership roleMembership = RoleMembership.Builder.create(
1603                     roleMemberBo.getRoleId(),
1604                     roleMemberBo.getId(),
1605                     roleMemberBo.getMemberId(),
1606                     roleMemberBo.getType(),
1607                     roleMemberBo.getAttributes()).build();
1608 
1609             // if the role type service is null, assume that all qualifiers match
1610             if (getRoleTypeService(roleMemberBo.getRoleId()) == null) {
1611                 return true;
1612             }
1613             List<RoleMembership> lrmi = roleIdToMembershipMap.get(roleMembership.getRoleId());
1614             if (lrmi == null) {
1615                 lrmi = new ArrayList<RoleMembership>();
1616                 roleIdToMembershipMap.put(roleMembership.getRoleId(), lrmi);
1617             }
1618             lrmi.add(roleMembership);
1619         }
1620         return false;
1621     }
1622 
1623     /**
1624      * Retrieves a KimDelegationImpl object by its ID. If the delegateBo already exists in the cache, this method will return the cached
1625      * version; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
1626      */
1627     protected DelegateTypeBo getKimDelegationImpl(String delegationId) {
1628         if (StringUtils.isBlank(delegationId)) {
1629             return null;
1630         }
1631 
1632         return getBusinessObjectService().findByPrimaryKey(DelegateTypeBo.class,
1633                 Collections.singletonMap(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId));
1634     }
1635 
1636     protected DelegationTypeService getDelegationTypeService(String delegationId) {
1637         DelegationTypeService service = null;
1638         DelegateTypeBo delegateBo = getKimDelegationImpl(delegationId);
1639         KimType delegationType = KimApiServiceLocator.getKimTypeInfoService().getKimType(delegateBo.getKimTypeId());
1640         if (delegationType != null) {
1641             KimTypeService tempService = KimFrameworkServiceLocator.getKimTypeService(delegationType);
1642             if (tempService != null && tempService instanceof DelegationTypeService) {
1643                 service = (DelegationTypeService) tempService;
1644             } else {
1645                 LOG.error("Service returned for type " + delegationType + "(" + delegationType.getName() + ") was not a DelegationTypeService.  Was a " + (tempService != null ? tempService.getClass() : "(null)"));
1646             }
1647         } else { // delegateBo has no type - default to role type if possible
1648             RoleTypeService roleTypeService = getRoleTypeService(delegateBo.getRoleId());
1649             if (roleTypeService != null && roleTypeService instanceof DelegationTypeService) {
1650                 service = (DelegationTypeService) roleTypeService;
1651             }
1652         }
1653         return service;
1654     }
1655 
1656     protected Collection<RoleMembership> getNestedRoleMembers(Map<String, String> qualification, RoleMembership rm, Set<String> foundRoleTypeMembers) {
1657         // If this role has already been traversed, skip it
1658         if (foundRoleTypeMembers.contains(rm.getMemberId())) {
1659             return new ArrayList<RoleMembership>();  // return an empty list
1660         }
1661         foundRoleTypeMembers.add(rm.getMemberId());
1662 
1663         ArrayList<String> roleIdList = new ArrayList<String>(1);
1664         roleIdList.add(rm.getMemberId());
1665 
1666         // get the list of members from the nested role - ignore delegations on those sub-roles
1667         Collection<RoleMembership> currentNestedRoleMembers = getRoleMembers(roleIdList, qualification, false, foundRoleTypeMembers);
1668 
1669         // add the roles whose members matched to the list for delegateBo checks later
1670         Collection<RoleMembership> returnRoleMembers = new ArrayList<RoleMembership>();
1671         for (RoleMembership roleMembership : currentNestedRoleMembers) {
1672             RoleMembership.Builder rmBuilder = RoleMembership.Builder.create(roleMembership);
1673 
1674             // use the member ID of the parent role (needed for responsibility joining)
1675             rmBuilder.setId(rm.getId());
1676             // store the role ID, so we know where this member actually came from
1677             rmBuilder.setRoleId(rm.getRoleId());
1678             rmBuilder.setEmbeddedRoleId(rm.getMemberId());
1679             returnRoleMembers.add(rmBuilder.build());
1680         }
1681         return returnRoleMembers;
1682     }
1683 
1684     /**
1685      * Retrieves a KimDelegationMemberImpl object by its ID and the ID of the delegation it belongs to. If the delegation member exists in the cache,
1686      * this method will return the cached one; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
1687      */
1688     protected DelegateMemberBo getKimDelegationMemberImplByDelegationAndId(String delegationId, String delegationMemberId) {
1689         if (StringUtils.isBlank(delegationId) || StringUtils.isBlank(delegationMemberId)) {
1690             return null;
1691         }
1692 
1693         Map<String, String> searchCriteria = new HashMap<String, String>();
1694         searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId);
1695         searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMemberId);
1696         List<DelegateMemberBo> memberList =
1697                 (List<DelegateMemberBo>) getBusinessObjectService().findMatching(DelegateMemberBo.class, searchCriteria);
1698         if (memberList != null && !memberList.isEmpty()) {
1699             return memberList.get(0);
1700         }
1701         return null;
1702     }
1703 
1704     private List<RoleMemberBo> getStoredRoleMembersUsingExactMatchOnQualification(String principalId, List<String> groupIds, List<String> roleIds, Map<String, String> qualification) {
1705         List<String> copyRoleIds = new ArrayList<String>(roleIds);
1706         List<RoleMemberBo> roleMemberBoList = new ArrayList<RoleMemberBo>();
1707 
1708         for (String roleId : roleIds) {
1709             RoleTypeService roleTypeService = getRoleTypeService(roleId);
1710             if (roleTypeService != null) {
1711                 try {
1712                     List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
1713                     if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
1714                         copyRoleIds.remove(roleId);
1715                         roleMemberBoList.addAll(getStoredRoleMembersForRoleIdsWithFilters(Collections.singletonList(roleId), principalId, groupIds, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
1716                     }
1717                 } catch (Exception e) {
1718                     LOG.warn("Caught exception when attempting to invoke a role type service for role " + roleId, e);
1719                 }
1720             }
1721         }
1722         if (CollectionUtils.isNotEmpty(copyRoleIds)) {
1723             roleMemberBoList.addAll(getStoredRoleMembersForRoleIdsWithFilters(copyRoleIds, principalId, groupIds, null));
1724         }
1725         return roleMemberBoList;
1726     }
1727 
1728     private List<RoleMemberBo> getStoredRoleGroupsUsingExactMatchOnQualification(List<String> groupIds, String roleId, Map<String, String> qualification) {
1729         Set<String> roleIds = new HashSet<String>();
1730         if (roleId != null) {
1731             roleIds.add(roleId);
1732         }
1733         return getStoredRoleGroupsUsingExactMatchOnQualification(groupIds, roleIds, qualification);
1734     }
1735 
1736     private List<RoleMemberBo> getStoredRoleGroupsUsingExactMatchOnQualification(List<String> groupIds, Set<String> roleIds, Map<String, String> qualification) {
1737         List<String> copyRoleIds = new ArrayList<String>(roleIds);
1738         List<RoleMemberBo> roleMemberBos = new ArrayList<RoleMemberBo>();
1739 
1740         for (String roleId : roleIds) {
1741             RoleTypeService roleTypeService = getRoleTypeService(roleId);
1742             if (roleTypeService != null) {
1743                 try {
1744                     List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
1745                     if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
1746                         copyRoleIds.remove(roleId);
1747                         roleMemberBos.addAll(getStoredRoleGroupsForGroupIdsAndRoleIds(Collections.singletonList(roleId), groupIds, populateQualifiersForExactMatch(qualification, attributesForExactMatch)));
1748                     }
1749                 } catch (Exception e) {
1750                     LOG.warn("Caught exception when attempting to invoke a role type service for role " + roleId, e);
1751                 }
1752             }
1753         }
1754         if (CollectionUtils.isNotEmpty(copyRoleIds)) {
1755             roleMemberBos.addAll(getStoredRoleGroupsForGroupIdsAndRoleIds(copyRoleIds, groupIds, null));
1756         }
1757         return roleMemberBos;
1758     }
1759 
1760     private List<DelegateMember> getDelegateMembersForDelegation(DelegateTypeBo delegateBo) {
1761         if (delegateBo == null || delegateBo.getMembers() == null) {return null;}
1762         List<DelegateMember> delegateMembersReturnList = new ArrayList<DelegateMember>();
1763         for (DelegateMemberBo delegateMemberBo : delegateBo.getMembers()) {
1764             //FIXME: What is up with this!?!
1765             DelegateMember delegateMember = getDelegateCompleteInfo(delegateBo, delegateMemberBo);
1766 
1767             delegateMembersReturnList.add(DelegateMemberBo.to(delegateMemberBo));
1768         }
1769         return Collections.unmodifiableList(delegateMembersReturnList);
1770     }
1771 
1772     private DelegateMember getDelegateCompleteInfo(DelegateTypeBo delegateBo, DelegateMemberBo delegateMemberBo) {
1773         if (delegateBo == null || delegateMemberBo == null) {return null;}
1774 
1775         DelegateMember.Builder delegateMemberBuilder = DelegateMember.Builder.create(delegateMemberBo);
1776         delegateMemberBuilder.setType(delegateMemberBo.getType());
1777         return delegateMemberBuilder.build();
1778     }
1779 
1780     @Override
1781     public RoleMember assignPrincipalToRole(String principalId,
1782             String namespaceCode, String roleName, Map<String, String> qualifier)
1783             throws RiceIllegalArgumentException {
1784         incomingParamCheck(principalId, "principalId");
1785         incomingParamCheck(namespaceCode, "namespaceCode");
1786         incomingParamCheck(roleName, "roleName");
1787         incomingParamCheck(qualifier, "qualifier");
1788 
1789         // look up the role
1790         RoleBoLite role = getRoleBoLiteByName(namespaceCode, roleName);
1791 
1792         // check that identical member does not already exist
1793         List<RoleMember> membersMatchByExactQualifiers = doAnyMemberRecordsMatchByExactQualifier(role, principalId, memberTypeToRoleDaoActionMap.get(MemberType.PRINCIPAL.getCode()), qualifier);
1794         if (CollectionUtils.isNotEmpty(membersMatchByExactQualifiers)) {
1795             return membersMatchByExactQualifiers.get(0);
1796         }
1797         List<String> roleIds = new ArrayList<String>();
1798         roleIds.add(role.getId());
1799         List<RoleMemberBo> roleMembers = getRoleDao().getRoleMembersForRoleIds(roleIds, MemberType.PRINCIPAL.getCode(),
1800                 qualifier);
1801         RoleMember anyMemberMatch = doAnyMemberRecordsMatch( roleMembers, principalId, MemberType.PRINCIPAL.getCode(), qualifier );
1802         if (null != anyMemberMatch) {
1803             return anyMemberMatch;
1804         }
1805 
1806         // create the new role member object
1807         RoleMemberBo newRoleMember = new RoleMemberBo();
1808 
1809         newRoleMember.setRoleId(role.getId());
1810         newRoleMember.setMemberId(principalId);
1811         newRoleMember.setType(MemberType.PRINCIPAL);
1812 
1813         // build role member attribute objects from the given Map<String, String>
1814         addMemberAttributeData(newRoleMember, qualifier, role.getKimTypeId());
1815 
1816         // add row to member table
1817         // When members are added to roles, clients must be notified.
1818         return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(newRoleMember));
1819     }
1820 
1821     @Override
1822     public RoleMember assignGroupToRole(String groupId, String namespaceCode,
1823             String roleName, Map<String, String> qualifier) throws RiceIllegalStateException {
1824         incomingParamCheck(groupId, "groupId");
1825         incomingParamCheck(namespaceCode, "namespaceCode");
1826         incomingParamCheck(roleName, "roleName");
1827         incomingParamCheck(qualifier, "qualifier");
1828 
1829         // look up the role
1830         RoleBo role = getRoleBoByName(namespaceCode, roleName);
1831 
1832         // check that identical member does not already exist
1833         List<RoleMember> membersMatchByExactQualifiers = doAnyMemberRecordsMatchByExactQualifier(role, groupId, memberTypeToRoleDaoActionMap.get(MemberType.GROUP.getCode()), qualifier);
1834         if (CollectionUtils.isNotEmpty(membersMatchByExactQualifiers)) {
1835             return membersMatchByExactQualifiers.get(0);
1836         }
1837         RoleMember anyMemberMatch = doAnyMemberRecordsMatch( role.getMembers(), groupId, MemberType.GROUP.getCode(), qualifier );
1838         if (null != anyMemberMatch) {
1839             return anyMemberMatch;
1840         }
1841 
1842         // create the new role member object
1843         RoleMemberBo newRoleMember = new RoleMemberBo();
1844         newRoleMember.setRoleId(role.getId());
1845         newRoleMember.setMemberId(groupId);
1846         newRoleMember.setType(MemberType.GROUP);
1847 
1848         // build role member attribute objects from the given Map<String, String>
1849         addMemberAttributeData(newRoleMember, qualifier, role.getKimTypeId());
1850 
1851         // When members are added to roles, clients must be notified.
1852         return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(newRoleMember));
1853     }
1854 
1855     @Override
1856     public RoleMember assignRoleToRole(String roleId,
1857             String namespaceCode, String roleName, Map<String, String> qualifier)
1858             throws RiceIllegalStateException {
1859         incomingParamCheck(roleId, "roleId");
1860         incomingParamCheck(namespaceCode, "namespaceCode");
1861         incomingParamCheck(roleName, "roleName");
1862         incomingParamCheck(qualifier, "qualifier");
1863 
1864         // look up the roleBo
1865         RoleBo roleBo = getRoleBoByName(namespaceCode, roleName);
1866 
1867         // check that identical member does not already exist
1868         List<RoleMember> membersMatchByExactQualifiers = doAnyMemberRecordsMatchByExactQualifier(roleBo, roleId, memberTypeToRoleDaoActionMap.get(MemberType.ROLE.getCode()), qualifier);
1869         if (CollectionUtils.isNotEmpty(membersMatchByExactQualifiers)) {
1870             return membersMatchByExactQualifiers.get(0);
1871         }
1872         RoleMember anyMemberMatch = doAnyMemberRecordsMatch( roleBo.getMembers(), roleId, MemberType.ROLE.getCode(), qualifier);
1873         if (null != anyMemberMatch) {
1874             return anyMemberMatch;
1875         }
1876 
1877 
1878         // Check to make sure this doesn't create a circular membership
1879         if (!checkForCircularRoleMembership(roleId, roleBo)) {
1880             throw new IllegalArgumentException("Circular roleBo reference.");
1881         }
1882         // create the new roleBo member object
1883         RoleMemberBo newRoleMember = new RoleMemberBo();
1884         newRoleMember.setRoleId(roleBo.getId());
1885         newRoleMember.setMemberId(roleId);
1886         newRoleMember.setType(MemberType.ROLE);
1887         // build roleBo member attribute objects from the given Map<String, String>
1888         addMemberAttributeData(newRoleMember, qualifier, roleBo.getKimTypeId());
1889 
1890         // When members are added to roles, clients must be notified.
1891         return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(newRoleMember));
1892     }
1893 
1894     @Override
1895     public RoleMember createRoleMember(RoleMember roleMember) throws RiceIllegalStateException {
1896         incomingParamCheck(roleMember, "roleMember");
1897 
1898         if (StringUtils.isNotBlank(roleMember.getId()) && getRoleMemberBo(roleMember.getId()) != null) {
1899             throw new RiceIllegalStateException("the roleMember to create already exists: " + roleMember);
1900         }
1901 
1902         String kimTypeId = getRoleBoLite(roleMember.getRoleId()).getKimTypeId();
1903         List<RoleMemberAttributeDataBo> attrBos = Collections.emptyList();
1904         attrBos = KimAttributeDataBo.createFrom(RoleMemberAttributeDataBo.class, roleMember.getAttributes(), kimTypeId);
1905 
1906         RoleMemberBo bo = RoleMemberBo.from(roleMember);
1907         bo.setAttributeDetails(attrBos);
1908         return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(bo));
1909     }
1910 
1911     @Override
1912     public RoleMember updateRoleMember(@WebParam(
1913             name = "roleMember") RoleMember roleMember) throws RiceIllegalArgumentException, RiceIllegalStateException {
1914         incomingParamCheck(roleMember, "roleMember");
1915 
1916         RoleMemberBo originalRoleMemberBo = null;
1917         if (StringUtils.isNotBlank(roleMember.getId())) {
1918             originalRoleMemberBo = getRoleMemberBo(roleMember.getId());
1919         }
1920         if (StringUtils.isBlank(roleMember.getId()) || originalRoleMemberBo == null) {
1921             throw new RiceIllegalStateException("the roleMember to update does not exists: " + roleMember);
1922         }
1923 
1924         String kimTypeId = getRoleBoLite(roleMember.getRoleId()).getKimTypeId();
1925         List<RoleMemberAttributeDataBo> attrBos = Collections.emptyList();
1926         attrBos = KimAttributeDataBo.createFrom(RoleMemberAttributeDataBo.class, roleMember.getAttributes(), kimTypeId);
1927 
1928         RoleMemberBo bo = RoleMemberBo.from(roleMember);
1929         List<RoleMemberAttributeDataBo> updateAttrBos =   new ArrayList<RoleMemberAttributeDataBo>();
1930 
1931         boolean matched = false;
1932         for (RoleMemberAttributeDataBo newRoleMemberAttrDataBo :  attrBos) {
1933             for (RoleMemberAttributeDataBo oldRoleMemberAttrDataBo :  originalRoleMemberBo.getAttributeDetails()) {
1934                 if (newRoleMemberAttrDataBo.getKimTypeId().equals(oldRoleMemberAttrDataBo.getKimTypeId()) &&
1935                         newRoleMemberAttrDataBo.getKimAttributeId().equals(oldRoleMemberAttrDataBo.getKimAttributeId())) {
1936                     newRoleMemberAttrDataBo.setAssignedToId(oldRoleMemberAttrDataBo.getAssignedToId());
1937                     newRoleMemberAttrDataBo.setVersionNumber(oldRoleMemberAttrDataBo.getVersionNumber());
1938                     newRoleMemberAttrDataBo.setId(oldRoleMemberAttrDataBo.getId());
1939                     updateAttrBos.add(newRoleMemberAttrDataBo);
1940                     matched = true;
1941                     break;
1942                 }
1943             }
1944             if (!matched) {
1945                 updateAttrBos.add(newRoleMemberAttrDataBo);
1946             } else  {
1947                 matched = false;
1948             }
1949         }
1950 
1951         bo.setAttributeDetails(updateAttrBos);
1952 
1953         return RoleMemberBo.to(getResponsibilityInternalService().saveRoleMember(bo));
1954     }
1955 
1956     @Override
1957     public DelegateMember updateDelegateMember(@WebParam(
1958             name = "delegateMember") DelegateMember delegateMember) throws RiceIllegalArgumentException, RiceIllegalStateException {
1959 
1960         //check delegateMember not empty
1961         incomingParamCheck(delegateMember, "delegateMember");
1962 
1963         //check delegate exists
1964         String delegationId =  delegateMember.getDelegationId();
1965         incomingParamCheck(delegationId,"delegationId");
1966         DelegateTypeBo delegate = getKimDelegationImpl(delegationId);
1967         DelegateMemberBo  originalDelegateMemberBo = null;
1968         String delegationMemberId = delegateMember.getDelegationMemberId();
1969         if (StringUtils.isNotEmpty(delegationMemberId)) {
1970             originalDelegateMemberBo = getDelegateMemberBo(delegateMember.getDelegationMemberId());
1971         }
1972         if(delegate==null)   {
1973             throw new RiceIllegalStateException("the delegate does not exist: " + delegationId);
1974         }
1975 
1976         //save the delegateMember  (actually updates)
1977         String kimTypeId = getRoleBoLite(delegate.getRoleId()).getKimTypeId();
1978         List<DelegateMemberAttributeDataBo> attrBos = Collections.emptyList();
1979         attrBos = KimAttributeDataBo.createFrom(DelegateMemberAttributeDataBo.class, delegateMember.getAttributes(), kimTypeId);
1980         DelegateMemberBo bo = DelegateMemberBo.from(delegateMember);
1981 
1982         List<DelegateMemberAttributeDataBo> updateAttrBos =   new ArrayList<DelegateMemberAttributeDataBo>();
1983 
1984         boolean matched = false;
1985         if (originalDelegateMemberBo !=null ) {
1986             bo.setVersionNumber(originalDelegateMemberBo.getVersionNumber());
1987             for (DelegateMemberAttributeDataBo newDelegateMemberAttrDataBo :  attrBos) {
1988                 for (DelegateMemberAttributeDataBo oldDelegateMemberAttrDataBo :  originalDelegateMemberBo.getAttributeDetails()) {
1989                     if (newDelegateMemberAttrDataBo.getKimTypeId().equals(oldDelegateMemberAttrDataBo.getKimTypeId()) &&
1990                             newDelegateMemberAttrDataBo.getKimAttributeId().equals(oldDelegateMemberAttrDataBo.getKimAttributeId())) {
1991                         newDelegateMemberAttrDataBo.setAssignedToId(oldDelegateMemberAttrDataBo.getAssignedToId());
1992                         newDelegateMemberAttrDataBo.setVersionNumber(oldDelegateMemberAttrDataBo.getVersionNumber());
1993                         newDelegateMemberAttrDataBo.setId(oldDelegateMemberAttrDataBo.getId());
1994                         updateAttrBos.add(newDelegateMemberAttrDataBo);
1995                         matched = true;
1996                         break;
1997                     }
1998                 }
1999                 if (!matched) {
2000                     updateAttrBos.add(newDelegateMemberAttrDataBo);
2001                 } else  {
2002                     matched = false;
2003                 }
2004             }
2005         }
2006 
2007         bo.setAttributeDetails(updateAttrBos);
2008         return DelegateMemberBo.to(getResponsibilityInternalService().saveDelegateMember(bo));
2009     }
2010 
2011     @Override
2012     public DelegateMember createDelegateMember(@WebParam(
2013             name = "delegateMember") DelegateMember delegateMember) throws RiceIllegalArgumentException, RiceIllegalStateException {
2014         //ensure object not empty
2015         incomingParamCheck(delegateMember, "delegateMember");
2016 
2017         //check key is null
2018         if(delegateMember.getDelegationMemberId()!=null )   {
2019             throw new RiceIllegalStateException("the delegate member already exists: " + delegateMember.getDelegationMemberId());
2020         }
2021 
2022         //check delegate exists
2023         String delegationId =  delegateMember.getDelegationId();
2024         incomingParamCheck(delegationId,"delegationId");
2025         DelegateTypeBo delegate = getKimDelegationImpl(delegationId);
2026         if(delegate==null)   {
2027             throw new RiceIllegalStateException("the delegate does not exist: " + delegationId);
2028         }
2029 
2030         //check member exists
2031         String memberId = delegateMember.getMemberId();
2032         incomingParamCheck(memberId,"memberId");
2033         Principal kPrincipal = KimApiServiceLocator.getIdentityService().getPrincipal(memberId);
2034         if(kPrincipal==null){
2035             throw new RiceIllegalStateException("the user does not exist: " + memberId);
2036         }
2037 
2038         //create member delegate
2039         String kimTypeId = getRoleBoLite(delegate.getRoleId()).getKimTypeId();
2040         List<DelegateMemberAttributeDataBo> attrBos = Collections.emptyList();
2041         attrBos = KimAttributeDataBo.createFrom(DelegateMemberAttributeDataBo.class, delegateMember.getAttributes(), kimTypeId);
2042         DelegateMemberBo bo = DelegateMemberBo.from(delegateMember);
2043         bo.setAttributeDetails(attrBos);
2044         return DelegateMemberBo.to(getResponsibilityInternalService().saveDelegateMember(bo));
2045     }
2046 
2047     @Override
2048     public void removeDelegateMembers(@WebParam(
2049             name = "delegateMembers") List<DelegateMember> delegateMembers) throws RiceIllegalArgumentException, RiceIllegalStateException {
2050         incomingParamCheck(delegateMembers, "delegateMembers");
2051         for (DelegateMember delegateMember : delegateMembers) {
2052             DelegateMember.Builder delegateMemberInfo = DelegateMember.Builder.create();
2053             delegateMemberInfo.setDelegationMemberId(delegateMember.getDelegationMemberId());
2054             delegateMemberInfo.setAttributes(delegateMember.getAttributes());
2055             delegateMemberInfo.setDelegationId(delegateMember.getDelegationId());
2056             delegateMemberInfo.setMemberId(delegateMember.getMemberId());
2057             delegateMemberInfo.setRoleMemberId(delegateMember.getRoleMemberId());
2058             delegateMemberInfo.setType(delegateMember.getType());
2059             delegateMemberInfo.setActiveFromDate(delegateMember.getActiveFromDate());
2060             delegateMemberInfo.setActiveToDate(DateTime.now());
2061             updateDelegateMember(delegateMemberInfo.build());
2062         }
2063     }
2064 
2065     @Override
2066     public RoleResponsibilityAction createRoleResponsibilityAction(RoleResponsibilityAction roleResponsibilityAction)
2067             throws RiceIllegalArgumentException, RiceIllegalStateException {
2068         incomingParamCheck(roleResponsibilityAction, "roleResponsibilityAction");
2069 
2070 
2071         if (StringUtils.isNotBlank(roleResponsibilityAction.getId())
2072                 && getRoleResponsibilityActionBo(roleResponsibilityAction.getId()) != null) {
2073             throw new RiceIllegalStateException("the roleResponsibilityAction to create already exists: " + roleResponsibilityAction);
2074         }
2075 
2076         RoleResponsibilityActionBo bo = RoleResponsibilityActionBo.from(roleResponsibilityAction);
2077         return RoleResponsibilityActionBo.to(getBusinessObjectService().save(bo));
2078     }
2079 
2080     /**
2081      * Queues ActionRequest refresh/regeneration for RoleResponsbilityAction change
2082      * @param bo the changed or deleted RoleResponsibilityActionBo
2083      */
2084     protected void updateActionRequestsForRoleResponsibilityActionChange(RoleResponsibilityActionBo bo) {
2085         RoleResponsibilityBo rr = bo.getRoleResponsibility();
2086         if (rr != null) {
2087             getResponsibilityInternalService().updateActionRequestsForResponsibilityChange(Collections.singleton(rr.getResponsibilityId()));
2088         }
2089     }
2090 
2091     @Override
2092     public RoleResponsibilityAction updateRoleResponsibilityAction(RoleResponsibilityAction roleResponsibilityAction)
2093             throws RiceIllegalArgumentException, RiceIllegalStateException {
2094         incomingParamCheck(roleResponsibilityAction, "roleResponsibilityAction");
2095 
2096         if (StringUtils.isBlank(roleResponsibilityAction.getId()) || getRoleResponsibilityActionBo(roleResponsibilityAction.getId()) == null) {
2097             throw new RiceIllegalStateException("the roleResponsibilityAction to create does not exist: " + roleResponsibilityAction);
2098         }
2099 
2100         RoleResponsibilityActionBo bo = RoleResponsibilityActionBo.from(roleResponsibilityAction);
2101         roleResponsibilityAction = RoleResponsibilityActionBo.to(getBusinessObjectService().save(bo));
2102 
2103         // update action requests
2104         updateActionRequestsForRoleResponsibilityActionChange(bo);
2105 
2106         return roleResponsibilityAction;
2107     }
2108 
2109     @Override
2110     public void deleteRoleResponsibilityAction(String roleResponsibilityActionId)
2111             throws RiceIllegalArgumentException, RiceIllegalStateException {
2112         incomingParamCheck(roleResponsibilityActionId, "roleResponsibilityActionId");
2113 
2114         RoleResponsibilityActionBo bo = getRoleResponsibilityActionBo(roleResponsibilityActionId);
2115         if (StringUtils.isBlank(roleResponsibilityActionId) || bo == null) {
2116             throw new RiceIllegalStateException("the roleResponsibilityAction to delete does not exist: " + roleResponsibilityActionId);
2117         }
2118 
2119         getBusinessObjectService().delete(bo);
2120 
2121         // update action requests
2122         updateActionRequestsForRoleResponsibilityActionChange(bo);
2123     }
2124 
2125     @Override
2126     public DelegateType createDelegateType(DelegateType delegateType) throws RiceIllegalArgumentException, RiceIllegalStateException {
2127         incomingParamCheck(delegateType, "delegateType");
2128 
2129         if (StringUtils.isNotBlank(delegateType.getDelegationId())
2130                 && getDelegateTypeByDelegationId(delegateType.getDelegationId()) != null) {
2131             throw new RiceIllegalStateException("the delegateType to create already exists: " + delegateType);
2132         }
2133 
2134         DelegateTypeBo bo = DelegateTypeBo.from(delegateType);
2135         return DelegateTypeBo.to(getBusinessObjectService().save(bo));
2136         // look up the role
2137         /*RoleBo role = getRoleBo(delegationType.getRoleId());
2138     	DelegateTypeBo delegation = getDelegationOfType(role.getId(), delegationType.getDelegationTypeCode());
2139     	// create the new role member object
2140     	DelegateMemberBo newDelegationMember = new DelegateMemberBo();
2141 
2142     	DelegateMemberBo origDelegationMember;
2143     	if(StringUtils.isNotEmpty(delegationMemberId)){
2144     		origDelegationMember = getDelegateMemberBo(delegationMemberId);
2145     	} else{
2146     		List<DelegateMemberBo> origDelegationMembers =
2147                     this.getDelegationMemberBoListByMemberAndDelegationId(memberId, delegation.getDelegationId());
2148 	    	origDelegationMember =
2149 	    		(origDelegationMembers!=null && !origDelegationMembers.isEmpty()) ? origDelegationMembers.get(0) : null;
2150     	}
2151     	if(origDelegationMember!=null){
2152     		newDelegationMember.setDelegationMemberId(origDelegationMember.getDelegationMemberId());
2153     		newDelegationMember.setVersionNumber(origDelegationMember.getVersionNumber());
2154     	}
2155     	newDelegationMember.setMemberId(memberId);
2156     	newDelegationMember.setDelegationId(delegation.getDelegationId());
2157     	newDelegationMember.setRoleMemberId(roleMemberId);
2158     	newDelegationMember.setTypeCode(memberTypeCode);
2159 		if (activeFromDate != null) {
2160 			newDelegationMember.setActiveFromDateValue(new java.sql.Timestamp(activeFromDate.getMillis()));
2161 		}
2162 		if (activeToDate != null) {
2163 			newDelegationMember.setActiveToDateValue(new java.sql.Timestamp(activeToDate.getMillis()));
2164 		}
2165 
2166     	// build role member attribute objects from the given Map<String, String>
2167     	addDelegationMemberAttributeData( newDelegationMember, qualifications, role.getKimTypeId() );
2168 
2169     	List<DelegateMemberBo> delegationMembers = new ArrayList<DelegateMemberBo>();
2170     	delegationMembers.add(newDelegationMember);
2171     	delegation.setMembers(delegationMembers);
2172 
2173     	getBusinessObjectService().save(delegation);
2174     	for(DelegateMemberBo delegationMember: delegation.getMembers()){
2175     		deleteNullDelegationMemberAttributeData(delegationMember.getAttributes());
2176     	}*/
2177     }
2178 
2179     @Override
2180     public DelegateType updateDelegateType(DelegateType delegateType) throws RiceIllegalArgumentException, RiceIllegalStateException {
2181         incomingParamCheck(delegateType, "delegateType");
2182 
2183         if (StringUtils.isBlank(delegateType.getDelegationId())
2184                 || getDelegateTypeByDelegationId(delegateType.getDelegationId()) == null) {
2185             throw new RiceIllegalStateException("the delegateType to update does not exist: " + delegateType);
2186         }
2187 
2188         DelegateTypeBo bo = DelegateTypeBo.from(delegateType);
2189         return DelegateTypeBo.to(getBusinessObjectService().save(bo));
2190     }
2191 
2192 
2193     private void removeRoleMembers(List<RoleMemberBo> members) {
2194         if(CollectionUtils.isNotEmpty(members)) {
2195             for ( RoleMemberBo rm : members ) {
2196                 getResponsibilityInternalService().removeRoleMember(rm);
2197             }
2198         }
2199     }
2200 
2201 
2202     private List<RoleMemberBo> getRoleMembersByDefaultStrategy(String roleId, String memberId, String memberTypeCode, Map<String, String> qualifier) {
2203         List<RoleMemberBo> rms = new ArrayList<RoleMemberBo>();
2204         List<RoleMemberBo> roleMem= getRoleDao().getRoleMembershipsForMemberId(memberTypeCode,memberId,qualifier);
2205         for ( RoleMemberBo rm : roleMem ) {
2206             if ( rm.getRoleId().equals(roleId) ) {
2207                 // if found, remove
2208                 rms.add(rm);
2209             }
2210         }
2211         return rms;
2212     }
2213 
2214     @Override
2215     public void removePrincipalFromRole(String principalId,
2216             String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalArgumentException {
2217         if (StringUtils.isBlank(principalId)) {
2218             throw new RiceIllegalArgumentException("principalId is null");
2219         }
2220 
2221         if (StringUtils.isBlank(namespaceCode)) {
2222             throw new RiceIllegalArgumentException("namespaceCode is null");
2223         }
2224 
2225         if (StringUtils.isBlank(roleName)) {
2226             throw new RiceIllegalArgumentException("roleName is null");
2227         }
2228 
2229         if (qualifier == null) {
2230             throw new RiceIllegalArgumentException("qualifier is null");
2231         }
2232         // look up the role
2233         RoleBoLite role = getRoleBoLiteByName(namespaceCode, roleName);
2234         // pull all the principal members
2235         // look for an exact qualifier match
2236         List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(role, principalId, memberTypeToRoleDaoActionMap.get(MemberType.PRINCIPAL.getCode()), qualifier);
2237         if(CollectionUtils.isEmpty(rms)) {
2238             rms = getRoleMembersByDefaultStrategy(role.getId(), principalId, MemberType.PRINCIPAL.getCode(), qualifier);
2239         }
2240         removeRoleMembers(rms);
2241     }
2242 
2243     @Override
2244     public void removeGroupFromRole(String groupId,
2245             String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalArgumentException {
2246         if (StringUtils.isBlank(groupId)) {
2247             throw new RiceIllegalArgumentException("groupId is null");
2248         }
2249 
2250         if (StringUtils.isBlank(namespaceCode)) {
2251             throw new RiceIllegalArgumentException("namespaceCode is null");
2252         }
2253 
2254         if (StringUtils.isBlank(roleName)) {
2255             throw new RiceIllegalArgumentException("roleName is null");
2256         }
2257 
2258         if (qualifier == null) {
2259             throw new RiceIllegalArgumentException("qualifier is null");
2260         }
2261 
2262         // look up the roleBo
2263         RoleBoLite roleBo = getRoleBoLiteByName(namespaceCode, roleName);
2264         // pull all the group roleBo members
2265         // look for an exact qualifier match
2266         List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(roleBo, groupId, memberTypeToRoleDaoActionMap.get(MemberType.GROUP.getCode()), qualifier);
2267         if(CollectionUtils.isEmpty(rms)) {
2268             rms = getRoleMembersByDefaultStrategy(roleBo.getId(), groupId, MemberType.GROUP.getCode(), qualifier);
2269         }
2270         removeRoleMembers(rms);
2271     }
2272 
2273     @Override
2274     public void removeRoleFromRole(String roleId,
2275             String namespaceCode, String roleName, Map<String, String> qualifier) throws RiceIllegalArgumentException {
2276         incomingParamCheck(roleId, "roleId");
2277         incomingParamCheck(namespaceCode, "namespaceCode");
2278         incomingParamCheck(roleName, "roleName");
2279         incomingParamCheck(qualifier, "qualifier");
2280 
2281 
2282         // look up the role
2283         RoleBoLite role = getRoleBoLiteByName(namespaceCode, roleName);
2284         // pull all the group role members
2285         // look for an exact qualifier match
2286         List<RoleMemberBo> rms = getRoleMembersByExactQualifierMatch(role, roleId, memberTypeToRoleDaoActionMap.get(MemberType.ROLE.getCode()), qualifier);
2287         if(CollectionUtils.isEmpty(rms)) {
2288             rms = getRoleMembersByDefaultStrategy(role.getId(), roleId, MemberType.ROLE.getCode(), qualifier);
2289         }
2290         removeRoleMembers(rms);
2291     }
2292 
2293     @Override
2294     public void assignPermissionToRole(String permissionId, String roleId) throws RiceIllegalArgumentException {
2295         incomingParamCheck(permissionId, "permissionId");
2296         incomingParamCheck(roleId, "roleId");
2297 
2298         RolePermissionBo newRolePermission = new RolePermissionBo();
2299 
2300         Long nextSeq = KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S, RolePermissionBo.class);
2301 
2302         if (nextSeq == null) {
2303             LOG.error("Unable to get new role permission id from sequence " + KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S);
2304             throw new RuntimeException("Unable to get new role permission id from sequence " + KimConstants.SequenceNames.KRIM_ROLE_PERM_ID_S);
2305         }
2306 
2307         newRolePermission.setId(nextSeq.toString());
2308         newRolePermission.setRoleId(roleId);
2309         newRolePermission.setPermissionId(permissionId);
2310         newRolePermission.setActive(true);
2311 
2312         getBusinessObjectService().save(newRolePermission);
2313     }
2314 
2315     @Override
2316     public void revokePermissionFromRole(String permissionId, String roleId) throws RiceIllegalArgumentException {
2317         incomingParamCheck(permissionId, "permissionId");
2318         incomingParamCheck(roleId, "roleId");
2319 
2320         Map<String, Object> params = new HashMap<String, Object>();
2321         params.put("roleId", roleId);
2322         params.put("permissionId", permissionId);
2323         params.put("active", Boolean.TRUE);
2324         Collection<RolePermissionBo> rolePermissionBos = getBusinessObjectService().findMatching(RolePermissionBo.class, params);
2325         List<RolePermissionBo> rolePermsToSave = new ArrayList<RolePermissionBo>();
2326         for (RolePermissionBo rolePerm : rolePermissionBos) {
2327             rolePerm.setActive(false);
2328             rolePermsToSave.add(rolePerm);
2329         }
2330 
2331         getBusinessObjectService().save(rolePermsToSave);
2332     }
2333 
2334     protected void addMemberAttributeData(RoleMemberBo roleMember, Map<String, String> qualifier, String kimTypeId) {
2335         List<RoleMemberAttributeDataBo> attributes = new ArrayList<RoleMemberAttributeDataBo>();
2336         for (Map.Entry<String, String> entry : qualifier.entrySet()) {
2337             RoleMemberAttributeDataBo roleMemberAttrBo = new RoleMemberAttributeDataBo();
2338             roleMemberAttrBo.setAttributeValue(entry.getValue());
2339             roleMemberAttrBo.setKimTypeId(kimTypeId);
2340             roleMemberAttrBo.setAssignedToId(roleMember.getId());
2341             // look up the attribute ID
2342             roleMemberAttrBo.setKimAttributeId(getKimAttributeId(kimTypeId, entry.getKey()));
2343 
2344             Map<String, String> criteria = new HashMap<String, String>();
2345             criteria.put(KimConstants.PrimaryKeyConstants.KIM_ATTRIBUTE_ID, roleMemberAttrBo.getKimAttributeId());
2346             //criteria.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMember.getId());
2347             criteria.put("assignedToId", roleMember.getId());
2348             List<RoleMemberAttributeDataBo> origRoleMemberAttributes =
2349                     (List<RoleMemberAttributeDataBo>) getBusinessObjectService().findMatching(RoleMemberAttributeDataBo.class, criteria);
2350             RoleMemberAttributeDataBo origRoleMemberAttribute =
2351                     (origRoleMemberAttributes != null && !origRoleMemberAttributes.isEmpty()) ? origRoleMemberAttributes.get(0) : null;
2352             if (origRoleMemberAttribute != null) {
2353                 roleMemberAttrBo.setId(origRoleMemberAttribute.getId());
2354                 roleMemberAttrBo.setVersionNumber(origRoleMemberAttribute.getVersionNumber());
2355             }
2356             attributes.add(roleMemberAttrBo);
2357         }
2358         roleMember.setAttributeDetails(attributes);
2359     }
2360 
2361     protected void addDelegationMemberAttributeData( DelegateMemberBo delegationMember, Map<String, String> qualifier, String kimTypeId ) {
2362         List<DelegateMemberAttributeDataBo> attributes = new ArrayList<DelegateMemberAttributeDataBo>();
2363         for (  Map.Entry<String, String> entry : qualifier.entrySet() ) {
2364             DelegateMemberAttributeDataBo delegateMemberAttrBo = new DelegateMemberAttributeDataBo();
2365             delegateMemberAttrBo.setAttributeValue(entry.getValue());
2366             delegateMemberAttrBo.setKimTypeId(kimTypeId);
2367             delegateMemberAttrBo.setAssignedToId(delegationMember.getDelegationMemberId());
2368             // look up the attribute ID
2369             delegateMemberAttrBo.setKimAttributeId(getKimAttributeId(kimTypeId, entry.getKey()));
2370             Map<String, String> criteria = new HashMap<String, String>();
2371             criteria.put(KimConstants.PrimaryKeyConstants.KIM_ATTRIBUTE_ID, delegateMemberAttrBo.getKimAttributeId());
2372             criteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMember.getDelegationMemberId());
2373             List<DelegateMemberAttributeDataBo> origDelegationMemberAttributes =
2374                     (List<DelegateMemberAttributeDataBo>)getBusinessObjectService().findMatching(DelegateMemberAttributeDataBo.class, criteria);
2375             DelegateMemberAttributeDataBo origDelegationMemberAttribute =
2376                     (origDelegationMemberAttributes!=null && !origDelegationMemberAttributes.isEmpty()) ? origDelegationMemberAttributes.get(0) : null;
2377             if(origDelegationMemberAttribute!=null){
2378                 delegateMemberAttrBo.setId(origDelegationMemberAttribute.getId());
2379                 delegateMemberAttrBo.setVersionNumber(origDelegationMemberAttribute.getVersionNumber());
2380             }
2381             attributes.add( delegateMemberAttrBo );
2382         }
2383         delegationMember.setAttributeDetails( attributes );
2384     }
2385 
2386 
2387 
2388     // --------------------
2389     // Persistence Methods
2390     // --------------------
2391 
2392     private void deleteNullMemberAttributeData(List<RoleMemberAttributeDataBo> attributes) {
2393         List<RoleMemberAttributeDataBo> attributesToDelete = new ArrayList<RoleMemberAttributeDataBo>();
2394         for(RoleMemberAttributeDataBo attribute: attributes){
2395             if(attribute.getAttributeValue()==null){
2396                 attributesToDelete.add(attribute);
2397             }
2398         }
2399         getBusinessObjectService().delete(attributesToDelete);
2400     }
2401 
2402     private void deleteNullDelegationMemberAttributeData(List<DelegateMemberAttributeDataBo> attributes) {
2403         List<DelegateMemberAttributeDataBo> attributesToDelete = new ArrayList<DelegateMemberAttributeDataBo>();
2404 
2405         for(DelegateMemberAttributeDataBo attribute: attributes){
2406             if(attribute.getAttributeValue()==null){
2407                 attributesToDelete.add(attribute);
2408             }
2409         }
2410         getBusinessObjectService().delete(attributesToDelete);
2411     }
2412 
2413     protected void logPrincipalHasRoleCheck(String principalId, List<String> roleIds, Map<String, String> roleQualifiers ) {
2414         StringBuilder sb = new StringBuilder();
2415         sb.append(  '\n' );
2416         sb.append( "Has Role     : " ).append( roleIds ).append( '\n' );
2417         if ( roleIds != null ) {
2418             for ( String roleId : roleIds ) {
2419                 Role role = getRole( roleId );
2420                 if ( role != null ) {
2421                     sb.append( "        Name : " ).append( role.getNamespaceCode() ).append( '/').append( role.getName() );
2422                     sb.append( " (" ).append( roleId ).append( ')' );
2423                     sb.append( '\n' );
2424                 }
2425             }
2426         }
2427         sb.append( "   Principal : " ).append( principalId );
2428         if ( principalId != null ) {
2429             Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
2430             if ( principal != null ) {
2431                 sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' );
2432             }
2433         }
2434         sb.append( '\n' );
2435         sb.append( "     Details :\n" );
2436         if ( roleQualifiers != null ) {
2437             sb.append( roleQualifiers );
2438         } else {
2439             sb.append( "               [null]\n" );
2440         }
2441         if (LOG.isTraceEnabled()) {
2442             LOG.trace( sb.append(ExceptionUtils.getStackTrace(new Throwable())));
2443         } else {
2444             LOG.debug(sb.toString());
2445         }
2446     }
2447 
2448     private void incomingParamCheck(Object object, String name) {
2449         if (object == null) {
2450             throw new RiceIllegalArgumentException(name + " was null");
2451         } else if (object instanceof String
2452                 && StringUtils.isBlank((String) object)) {
2453             throw new RiceIllegalArgumentException(name + " was blank");
2454         }
2455     }
2456 
2457     /**
2458      * This gets the proxied version of the role service which will go through
2459      * Spring's caching mechanism for method calls rather than skipping it when
2460      * methods are called directly.
2461      *
2462      * @return The proxied role service
2463      */
2464     protected RoleService getProxiedRoleService() {
2465         if(this.proxiedRoleService == null) {
2466             this.proxiedRoleService = KimApiServiceLocator.getRoleService();
2467         }
2468         return this.proxiedRoleService;
2469     }
2470 
2471     /**
2472      * Sets the cache manager which this service implementation can for internal caching.
2473      * Calling this setter is optional, though the value passed to it must not be null.
2474      *
2475      * @param cacheManager the cache manager to use for internal caching, must not be null
2476      * @throws IllegalArgumentException if a null cache manager is passed
2477      */
2478     public void setCacheManager(CacheManager cacheManager) {
2479         if (cacheManager == null) {
2480             throw new IllegalArgumentException("cacheManager must not be null");
2481         }
2482         this.cacheManager = cacheManager;
2483     }
2484 
2485     private static class VersionedService<T> {
2486 
2487         String version;
2488         T service;
2489 
2490         VersionedService(String version, T service) {
2491             this.version = version;
2492             this.service = service;
2493         }
2494 
2495         T getService() {
2496             return this.service;
2497         }
2498 
2499         String getVersion() {
2500             return this.version;
2501         }
2502 
2503     }
2504 
2505     protected VersionedService<RoleTypeService> getVersionedRoleTypeService(KimType typeInfo) {
2506         QName serviceName = KimTypeUtils.resolveKimTypeServiceName(typeInfo.getServiceName());
2507         if (serviceName != null) {
2508             // default version since the base services have been available since then
2509             String version = CoreConstants.Versions.VERSION_2_0_0;
2510             RoleTypeService roleTypeService = null;
2511 
2512             try {
2513 
2514                 ServiceBus serviceBus = KsbApiServiceLocator.getServiceBus();
2515                 Endpoint endpoint = serviceBus.getEndpoint(serviceName);
2516                 if (endpoint != null) {
2517                     version = endpoint.getServiceConfiguration().getServiceVersion();
2518                 }
2519                 KimTypeService service = GlobalResourceLoader.getService(serviceName);
2520                 if (service != null && service instanceof RoleTypeService) {
2521                     roleTypeService = (RoleTypeService) service;
2522                 } else {
2523                     roleTypeService = (RoleTypeService) KimImplServiceLocator.getService("kimNoMembersRoleTypeService");
2524                 }
2525             } catch (Exception ex) {
2526                 roleTypeService = (RoleTypeService) KimImplServiceLocator.getService("kimNoMembersRoleTypeService");
2527             }
2528 
2529             return new VersionedService<RoleTypeService>(version, roleTypeService);
2530         }
2531 
2532         return null;
2533     }
2534 
2535     private Map<String, String> getNestedQualification(RoleBoLite memberRole, String namespaceCode, String roleName,
2536             String memberNamespaceCode, String memberName, Map<String, String> qualification,
2537             Map<String, String> memberQualification) {
2538         VersionedService<RoleTypeService> versionedRoleTypeService = getVersionedRoleTypeService(KimTypeBo.to(memberRole.getKimRoleType()));
2539         boolean versionOk = VersionHelper.compareVersion(versionedRoleTypeService.getVersion(),
2540                 CoreConstants.Versions.VERSION_2_3_4) != -1;
2541         if (versionOk) {
2542             return versionedRoleTypeService.getService().convertQualificationForMemberRolesAndMemberAttributes(namespaceCode, roleName,
2543                     memberNamespaceCode, memberName, qualification, memberQualification);
2544         } else {
2545             return versionedRoleTypeService.getService().convertQualificationForMemberRoles(namespaceCode, roleName,
2546                     memberNamespaceCode, memberName, qualification);
2547         }
2548 
2549     }
2550 
2551 }