View Javadoc

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