001    package org.kuali.rice.kim.impl.role;
002    
003    import org.apache.commons.collections.CollectionUtils;
004    import org.apache.commons.lang.StringUtils;
005    import org.kuali.rice.kew.api.action.DelegationType;
006    import org.kuali.rice.kim.api.common.delegate.DelegateMember;
007    import org.kuali.rice.kim.api.group.Group;
008    import org.kuali.rice.kim.api.group.GroupService;
009    import org.kuali.rice.kim.api.identity.principal.Principal;
010    import org.kuali.rice.kim.api.role.Role;
011    import org.kuali.rice.kim.api.role.RoleMember;
012    import org.kuali.rice.kim.api.role.RoleResponsibilityAction;
013    import org.kuali.rice.kim.api.services.IdentityService;
014    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
015    import org.kuali.rice.kim.framework.type.KimDelegationTypeService;
016    import org.kuali.rice.kim.framework.type.KimRoleTypeService;
017    import org.kuali.rice.kim.impl.common.attribute.KimAttributeBo;
018    import org.kuali.rice.kim.impl.common.delegate.DelegateBo;
019    import org.kuali.rice.kim.impl.common.delegate.DelegateMemberBo;
020    import org.kuali.rice.kim.impl.responsibility.ResponsibilityInternalService;
021    import org.kuali.rice.kim.impl.services.KIMServiceLocatorInternal;
022    import org.kuali.rice.kim.service.IdentityManagementNotificationService;
023    import org.kuali.rice.kim.util.KIMPropertyConstants;
024    import org.kuali.rice.kim.util.KimConstants;
025    import org.kuali.rice.krad.service.BusinessObjectService;
026    import org.kuali.rice.krad.service.KRADServiceLocator;
027    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
028    import org.kuali.rice.krad.service.LookupService;
029    import org.kuali.rice.krad.service.SequenceAccessorService;
030    import org.kuali.rice.krad.util.KRADPropertyConstants;
031    import org.kuali.rice.ksb.api.KsbApiServiceLocator;
032    import org.kuali.rice.ksb.api.cache.RiceCacheAdministrator;
033    
034    import javax.xml.namespace.QName;
035    import java.util.ArrayList;
036    import java.util.Collection;
037    import java.util.Collections;
038    import java.util.HashMap;
039    import java.util.HashSet;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.Set;
043    
044    public class RoleServiceBase {
045        protected static final String ROLE_IMPL_CACHE_PREFIX = "RoleImpl-ID-";
046        protected static final String ROLE_IMPL_BY_NAME_CACHE_PREFIX = "RoleImpl-Name-";
047        protected static final String ROLE_IMPL_CACHE_GROUP = "RoleImpl";
048    
049        protected static final String ROLE_MEMBER_IMPL_CACHE_PREFIX = "RoleMemberBo-ID-";
050        protected static final String ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX = "RoleMemberBo-List-";
051        protected static final String ROLE_MEMBER_IMPL_CACHE_GROUP = "RoleMemberBo";
052    
053        protected static final String DELEGATION_IMPL_CACHE_PREFIX = "DelegateBo-ID-";
054        protected static final String DELEGATION_IMPL_LIST_CACHE_PREFIX = "DelegateBo-List-";
055        protected static final String DELEGATION_IMPL_CACHE_GROUP = "DelegateBo";
056    
057        protected static final String DELEGATION_MEMBER_IMPL_CACHE_PREFIX = "DelegateMemberBo-ID-";
058        protected static final String DELEGATION_MEMBER_IMPL_BY_DLGN_AND_ID_CACHE_PREFIX = "DelegateMemberBo-DelegationAndId-";
059        protected static final String DELEGATION_MEMBER_IMPL_LIST_CACHE_PREFIX = "DelegateMemberBo-List-";
060        protected static final String DELEGATION_MEMBER_IMPL_LIST_BY_MBR_DLGN_CACHE_PREFIX = "DelegateMemberBo-List-MemberAndDelegationId-";
061        protected static final String DELEGATION_MEMBER_IMPL_CACHE_GROUP = "DelegateMemberBo";
062    
063        private BusinessObjectService businessObjectService;
064        private LookupService lookupService;
065        private RiceCacheAdministrator cacheAdministrator;
066        private SequenceAccessorService sequenceAccessorService;
067        private IdentityService identityService;
068        private GroupService groupService;
069        private ResponsibilityInternalService responsibilityInternalService;
070    
071        private Map<String, KimRoleTypeService> roleTypeServiceCache = Collections.synchronizedMap(new HashMap<String, KimRoleTypeService>());
072        private Map<String, KimDelegationTypeService> delegationTypeServiceCache = Collections.synchronizedMap(new HashMap<String, KimDelegationTypeService>());
073    
074        private Map<String, Boolean> applicationRoleTypeCache = Collections.synchronizedMap(new HashMap<String, Boolean>());
075        private RoleDao roleDao;
076    
077        /**
078         * A helper enumeration for indicating which KimRoleDao method to use when attempting to get role/delegation-related lists that are not in the cache.
079         *
080         * @author Kuali Rice Team (rice.collab@kuali.org)
081         */
082        public static enum RoleDaoAction {
083            ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS("principalMembers-"),
084            ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS("groupMembers-"),
085            ROLE_MEMBERS_FOR_ROLE_IDS("membersOfRole-"),
086            ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS("rolesAsMembers-"),
087            ROLE_MEMBERS_FOR_ROLE_IDS_WITH_FILTERS("roleIdsWithFilters-"),
088            DELEGATION_PRINCIPALS_FOR_PRINCIPAL_ID_AND_DELEGATION_IDS("delegationPrincipals-"),
089            DELEGATION_GROUPS_FOR_GROUP_IDS_AND_DELEGATION_IDS("delegationGroups-"),
090            DELEGATION_MEMBERS_FOR_DELEGATION_IDS("delegationMembers-");
091    
092            public final String DAO_ACTION_CACHE_PREFIX;
093    
094            private RoleDaoAction(String daoActionCachePrefix) {
095                this.DAO_ACTION_CACHE_PREFIX = daoActionCachePrefix;
096            }
097        }
098    
099        // -----------------------------------------------------------------------------------------------------------------
100        // Role Membership Caching Methods
101        // -----------------------------------------------------------------------------------------------------------------
102    
103        /**
104         * Generates a String key to use for storing or retrieving a RoleMemberBo to/from the cache.
105         *
106         * @param roleMemberId The ID of the RoleMemberBo to generate a key for.
107         * @return A cache key for the RoleMemberBo with the given ID.
108         */
109        protected String getRoleMemberCacheKey(String roleMemberId) {
110            return ROLE_MEMBER_IMPL_CACHE_PREFIX + roleMemberId;
111        }
112    
113        /**
114         * Generates a String key to use for storing or retrieving a list of RoleMemberBos to/from the cache. The key is generated by specifying
115         * certain properties that are common to all the RoleMemberBo instances in the list to be cached. Note that at least one common
116         * property will always be null; for instance, a role member cannot have a member ID that refers to both a principal and a group, so at least
117         * the principalId or the groupId parameter will have a null value passed in by the calling code in this RoleService implementation. Also,
118         * the value of the RoleDaoAction parameter passed in will affect which subsequent parameters will be used in generating the cache key.
119         *
120         * @param roleDaoAction  The RoleDaoAction signifying which KimRoleDao call found this list; will determine how and which parameters are used.
121         * @param roleId         The role ID (possibly as a member ID) shared among the members of the list; will be interpreted as an empty String if this is blank.
122         * @param principalId    The (principal) member ID shared among the members of the list; will be interpreted as an empty String if this is blank.
123         * @param groupId        The (group) member ID shared among the members of the list; will be interpreted as an empty String if this is blank.
124         * @param memberTypeCode The member type code shared among the members of the list; will be interpreted as an empty String if this is blank.
125         * @return A cache key for the RoleMemberBo list whose members share the given roleId, principalId, groupId, and memberTypeCode.
126         * @throws IllegalArgumentException if the RoleDaoAction parameter does not refer to a role-member-related enumeration value.
127         */
128        protected String getRoleMemberListCacheKey(RoleDaoAction roleDaoAction, String roleId, String principalId, String groupId, String memberTypeCode) {
129            switch (roleDaoAction) {
130                case ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS: // Search for principal role members only.
131                    return new StringBuilder(ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX).append(roleDaoAction.DAO_ACTION_CACHE_PREFIX).append(
132                            StringUtils.isBlank(roleId) ? "" : roleId).append('-').append(StringUtils.isBlank(principalId) ? "" : principalId).toString();
133                case ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS: // Search for group role members only.
134                    return new StringBuilder(ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX).append(roleDaoAction.DAO_ACTION_CACHE_PREFIX).append(
135                            StringUtils.isBlank(roleId) ? "" : roleId).append('-').append(StringUtils.isBlank(groupId) ? "" : groupId).toString();
136                case ROLE_MEMBERS_FOR_ROLE_IDS: // Search for role members with the given member type code.
137                    return new StringBuilder(ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX).append(roleDaoAction.DAO_ACTION_CACHE_PREFIX).append(
138                            StringUtils.isBlank(roleId) ? "" : roleId).append('-').append(StringUtils.isBlank(memberTypeCode) ? "" : memberTypeCode).toString();
139                case ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS: // Search for role members who are also roles.
140                    return new StringBuilder(ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX).append(roleDaoAction.DAO_ACTION_CACHE_PREFIX).append(
141                            StringUtils.isBlank(roleId) ? "" : roleId).toString();
142                case ROLE_MEMBERS_FOR_ROLE_IDS_WITH_FILTERS: // Search for role members that might be roles, principals, or groups.
143                    return new StringBuilder(ROLE_MEMBER_IMPL_LIST_CACHE_PREFIX).append(roleDaoAction.DAO_ACTION_CACHE_PREFIX).append(
144                            StringUtils.isBlank(roleId) ? "" : roleId).append('-').append(StringUtils.isBlank(principalId) ? "" : principalId).append(
145                            '-').append(StringUtils.isBlank(groupId) ? "" : groupId).append('-').append(
146                            StringUtils.isBlank(memberTypeCode) ? "" : memberTypeCode).toString();
147                default: // The daoActionToTake parameter is invalid; throw an exception.
148                    throw new IllegalArgumentException("The 'roleDaoAction' parameter cannot refer to a non-role-member-related value!");
149            }
150        }
151    
152        /**
153         * Converts the Qualifier Name/Value Role qualification set into Qualifier AttributeID/Value set
154         *
155         * @param qualification The original role qualification attribute set
156         * @return Converted Map<String, String> containing ID/value pairs
157         */
158        private Map<String, String> convertQualifierKeys(Map<String, String> qualification) {
159            Map<String, String> convertedQualification = new HashMap<String, String>();
160            if (qualification != null && CollectionUtils.isNotEmpty(qualification.keySet())) {
161                for (String attributeName : qualification.keySet()) {
162                    if (StringUtils.isNotEmpty(getKimAttributeId(attributeName))) {
163                        convertedQualification.put(getKimAttributeId(attributeName), qualification.get(attributeName));
164                    }
165                }
166            }
167            return convertedQualification;
168        }
169    
170        public Set<String> getRoleTypeRoleMemberIds(String roleId) {
171            Set<String> results = new HashSet();
172            getNestedRoleTypeMemberIds(roleId, results);
173            return results;
174        }
175    
176        protected void getNestedRoleTypeMemberIds(String roleId, Set members) throws RuntimeException {
177            ArrayList<String> roleList = new ArrayList<String>(1);
178            roleList.add(roleId);
179            List<RoleMemberBo> firstLevelMembers = getStoredRoleMembersForRoleIds(roleList, KimConstants.KimUIConstants.MEMBER_TYPE_ROLE_CODE, null);
180            for (RoleMemberBo member : firstLevelMembers) {
181                if (KimConstants.KimUIConstants.MEMBER_TYPE_ROLE_CODE.equals(member.getMemberTypeCode())) {
182                    if (!members.contains(member.getMemberId())) {
183                        members.add(member.getMemberId());
184                        getNestedRoleTypeMemberIds(member.getMemberId(), members);
185                    }
186                }
187            }
188        }
189    
190        public List<String> getMemberParentRoleIds(String memberType, String memberId) {
191            List<RoleMemberBo> parentRoleMembers = roleDao.getRoleMembershipsForMemberId(memberType, memberId, null);
192    
193            List<String> parentRoleIds = new ArrayList<String>(parentRoleMembers.size());
194            for (RoleMemberBo parentRoleMember : parentRoleMembers) {
195                parentRoleIds.add(parentRoleMember.getRoleId());
196            }
197    
198            return parentRoleIds;
199        }
200    
201        /**
202         * Retrieves a list of RoleMemberBo instances from the cache and/or the KimRoleDao as appropriate.
203         *
204         * @param daoActionToTake An indicator for which KimRoleDao method should be used to get the results if the desired RoleMemberBos are not cached.
205         * @param roleIds         The role IDs to filter by; may get used as the IDs for members that are also roles, depending on the daoActionToTake value.
206         * @param principalId     The principal ID to filter by; may get ignored depending on the daoActionToTake value.
207         * @param groupIds        The group IDs to filter by; may get ignored depending on the daoActionToTake value.
208         * @param memberTypeCode  The member type code to filter by; may get overridden depending on the daoActionToTake value.
209         * @param qualification   The original role qualification attribute set
210         * @return A list of RoleMemberBo instances based on the provided parameters.
211         * @throws IllegalArgumentException if daoActionToTake refers to an enumeration constant that is not role-member-related.
212         */
213        protected List<RoleMemberBo> getRoleMemberBoList(RoleDaoAction daoActionToTake, Collection<String> roleIds, String principalId,
214                                                         Collection<String> groupIds, String memberTypeCode, Map<String, String> qualification) {
215            List<RoleMemberBo> finalResults = new ArrayList<RoleMemberBo>();
216            List<RoleMemberCacheKeyHelper> searchKeys = new ArrayList<RoleMemberCacheKeyHelper>();
217            List<RoleMemberCacheKeyHelper> uncachedKeys = new ArrayList<RoleMemberCacheKeyHelper>();
218            Set<String> usedKeys = new HashSet<String>();
219            Map<String, String> convertedQualification = convertQualifierKeys(qualification);
220    
221            if (roleIds == null || roleIds.isEmpty()) {
222                roleIds = Collections.singletonList(null);
223            }
224            if (groupIds == null || groupIds.isEmpty()) {
225                groupIds = Collections.singletonList(null);
226            }
227    
228            // Attempt to find any pre-cached role members based on what KimRoleDao method call is desired.
229            switch (daoActionToTake) {
230                case ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS: // Search for principal role members only.
231                    for (String roleId : roleIds) {
232                        searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, principalId, null, Role.PRINCIPAL_MEMBER_TYPE));
233                    }
234                    break;
235                case ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS: // Search for group role members only.
236                    for (String roleId : roleIds) {
237                        for (String groupId : groupIds) {
238                            searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, null, groupId, Role.GROUP_MEMBER_TYPE));
239                        }
240                    }
241                    break;
242                case ROLE_MEMBERS_FOR_ROLE_IDS: // Search for role members with the given member type code.
243                    for (String roleId : roleIds) {
244                        searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, null, null, memberTypeCode));
245                    }
246                    break;
247                case ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS: // Search for role members who are also roles.
248                    for (String roleId : roleIds) {
249                        searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, null, null, Role.ROLE_MEMBER_TYPE));
250                    }
251                    break;
252                case ROLE_MEMBERS_FOR_ROLE_IDS_WITH_FILTERS: // Search for role members that might be roles, principals, or groups.
253                    for (String roleId : roleIds) {
254                        searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, null, null, Role.ROLE_MEMBER_TYPE));
255                        searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, principalId, null, Role.PRINCIPAL_MEMBER_TYPE));
256                        for (String groupId : groupIds) {
257                            searchKeys.add(new RoleMemberCacheKeyHelper(daoActionToTake, roleId, null, groupId, Role.GROUP_MEMBER_TYPE));
258                        }
259                    }
260                    break;
261                default: // The daoActionToTake parameter is invalid; throw an exception.
262                    throw new IllegalArgumentException("The 'daoActionToTake' parameter cannot refer to a non-role-member-related value!");
263            }
264    
265            // Attempt to find any pre-cached role members.
266            for (RoleMemberCacheKeyHelper searchKey : searchKeys) {
267                if (!usedKeys.contains(searchKey.getCacheKey())) {
268                    List<RoleMemberBo> tempMembers = (List<RoleMemberBo>) getCacheAdministrator().getFromCache(searchKey.getCacheKey());
269                    if (tempMembers != null) {
270                        finalResults.addAll(tempMembers);
271                    } else {
272                        uncachedKeys.add(searchKey);
273                    }
274                    usedKeys.add(searchKey.getCacheKey());
275                }
276            }
277    
278            // If any portion of the result set was not in the cache, then retrieve and cache the missing sections.
279            if (!uncachedKeys.isEmpty()) {
280                Set<String> uncachedRoleSet = new HashSet<String>();
281                Set<String> uncachedGroupSet = new HashSet<String>();
282                for (RoleMemberCacheKeyHelper uncachedKey : uncachedKeys) {
283                    if (uncachedKey.ROLE_ID != null) {
284                        uncachedRoleSet.add(uncachedKey.ROLE_ID);
285                    }
286                    if (uncachedKey.GROUP_ID != null) {
287                        uncachedGroupSet.add(uncachedKey.GROUP_ID);
288                    }
289                }
290    
291                List<String> uncachedRoles = (uncachedRoleSet.isEmpty()) ? null : new ArrayList<String>(uncachedRoleSet);
292                List<String> uncachedGroups = (uncachedGroupSet.isEmpty()) ? null : new ArrayList<String>(uncachedGroupSet);
293                List<RoleMemberBo> uncachedResults;
294    
295                // Retrieve the uncached RoleMemberBos via the appropriate RoleDao method.
296                switch (daoActionToTake) {
297                    case ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS: // Search for principal role members only.
298                        uncachedResults = roleDao.getRolePrincipalsForPrincipalIdAndRoleIds(uncachedRoles, principalId, convertedQualification);
299                        break;
300                    case ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS: // Search for group role members only.
301                        uncachedResults = roleDao.getRoleGroupsForGroupIdsAndRoleIds(uncachedRoles, uncachedGroups, convertedQualification);
302                        break;
303                    case ROLE_MEMBERS_FOR_ROLE_IDS: // Search for role members with the given member type code.
304                        uncachedResults = roleDao.getRoleMembersForRoleIds(uncachedRoles, memberTypeCode, convertedQualification);
305                        break;
306                    case ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS: // Search for role members who are also roles.
307                        uncachedResults = roleDao.getRoleMembershipsForRoleIdsAsMembers(uncachedRoles, convertedQualification);
308                        break;
309                    case ROLE_MEMBERS_FOR_ROLE_IDS_WITH_FILTERS: // Search for role members that might be roles, principals, or groups.
310                        uncachedResults = roleDao.getRoleMembersForRoleIdsWithFilters(uncachedRoles, principalId, uncachedGroups, convertedQualification);
311                        break;
312                    default: // This should never happen, since the previous switch block should handle this case appropriately.
313                        throw new IllegalArgumentException("The 'daoActionToTake' parameter cannot refer to a non-role-member-related value!");
314                }
315    
316                cacheRoleMemberLists(uncachedKeys, uncachedResults);
317                for (RoleMemberBo uncachedMember : uncachedResults) {
318                    addRoleMemberBoToCache(uncachedMember);
319                }
320                finalResults.addAll(uncachedResults);
321            }
322            return finalResults;
323        }
324    
325        /**
326         * Caches several Lists of role members that are constructed based on the given search keys. Note that a given List will not be cached if
327         * it contains any role members that belong to a role that disallows caching of its members.
328         *
329         * @param keysToCache    The keys of the role member Lists that will be used to store the uncached results.
330         * @param membersToCache The uncached role members.
331         */
332        private void cacheRoleMemberLists(List<RoleMemberCacheKeyHelper> keysToCache, List<RoleMemberBo> membersToCache) {
333            if (membersToCache == null) {
334                membersToCache = new ArrayList<RoleMemberBo>();
335            }
336            for (RoleMemberCacheKeyHelper keyToCache : keysToCache) {
337                List<RoleMemberBo> roleMembers = new ArrayList<RoleMemberBo>();
338    
339                // Cache the Lists that do not contain role members belonging to roles that forbid caching of their members.
340                if (RoleDaoAction.ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS.equals(keyToCache.ROLE_DAO_ACTION)) {
341                    boolean safeToCacheList = true;
342                    for (RoleMemberBo memberToCache : membersToCache) {
343                        if ((keyToCache.ROLE_ID == null || keyToCache.ROLE_ID.equals(memberToCache.getMemberId())) &&
344                                (keyToCache.MEMBER_TYPE_CODE == null || keyToCache.MEMBER_TYPE_CODE.equals(memberToCache.getMemberTypeCode()))) {
345                            if (shouldCacheMembersOfRole(memberToCache.getRoleId())) {
346                                roleMembers.add(memberToCache);
347                            } else {
348                                safeToCacheList = false;
349                                break;
350                            }
351                        }
352                    }
353                    if (safeToCacheList) {
354                        getCacheAdministrator().putInCache(keyToCache.getCacheKey(), roleMembers, ROLE_MEMBER_IMPL_CACHE_GROUP);
355                    }
356                } else if (keyToCache.ROLE_ID == null || shouldCacheMembersOfRole(keyToCache.ROLE_ID)) {
357                    for (RoleMemberBo memberToCache : membersToCache) {
358                        if ((keyToCache.ROLE_ID == null || keyToCache.ROLE_ID.equals(memberToCache.getRoleId())) &&
359                                (keyToCache.PRINCIPAL_ID == null || keyToCache.PRINCIPAL_ID.equals(memberToCache.getMemberId())) &&
360                                (keyToCache.GROUP_ID == null || keyToCache.GROUP_ID.equals(memberToCache.getMemberId())) &&
361                                (keyToCache.MEMBER_TYPE_CODE == null || keyToCache.MEMBER_TYPE_CODE.equals(memberToCache.getMemberTypeCode()))) {
362                            roleMembers.add(memberToCache);
363                        }
364                    }
365                    getCacheAdministrator().putInCache(keyToCache.getCacheKey(), roleMembers, ROLE_MEMBER_IMPL_CACHE_GROUP);
366                }
367            }
368        }
369    
370        /**
371         * Calls the KimRoleDao's "getRolePrincipalsForPrincipalIdAndRoleIds" method and/or retrieves any corresponding members from the cache.
372         */
373        protected List<RoleMemberBo> getStoredRolePrincipalsForPrincipalIdAndRoleIds(Collection<String> roleIds, String principalId, Map<String, String> qualification) {
374            return getRoleMemberBoList(RoleDaoAction.ROLE_PRINCIPALS_FOR_PRINCIPAL_ID_AND_ROLE_IDS, roleIds, principalId, null, null, qualification);
375        }
376    
377        /**
378         * Calls the KimRoleDao's "getRoleGroupsForGroupIdsAndRoleIds" method and/or retrieves any corresponding members from the cache.
379         */
380        protected List<RoleMemberBo> getStoredRoleGroupsForGroupIdsAndRoleIds(Collection<String> roleIds, Collection<String> groupIds, Map<String, String> qualification) {
381            return getRoleMemberBoList(RoleDaoAction.ROLE_GROUPS_FOR_GROUP_IDS_AND_ROLE_IDS, roleIds, null, groupIds, null, qualification);
382        }
383    
384        /**
385         * Calls the KimRoleDao's "getRoleMembersForRoleIds" method and/or retrieves any corresponding members from the cache.
386         */
387        protected List<RoleMemberBo> getStoredRoleMembersForRoleIds(Collection<String> roleIds, String memberTypeCode, Map<String, String> qualification) {
388            return getRoleMemberBoList(RoleDaoAction.ROLE_MEMBERS_FOR_ROLE_IDS, roleIds, null, null, memberTypeCode, qualification);
389        }
390    
391        /**
392         * Calls the KimRoleDao's "getRoleMembershipsForRoleIdsAsMembers" method and/or retrieves any corresponding members from the cache.
393         */
394        protected List<RoleMemberBo> getStoredRoleMembershipsForRoleIdsAsMembers(Collection<String> roleIds, Map<String, String> qualification) {
395            return getRoleMemberBoList(RoleDaoAction.ROLE_MEMBERSHIPS_FOR_ROLE_IDS_AS_MEMBERS, roleIds, null, null, null, qualification);
396        }
397    
398        /**
399         * Calls the KimRoleDao's "getRoleMembersForRoleIdsWithFilters" method and/or retrieves any corresponding members from the cache.
400         */
401        protected List<RoleMemberBo> getStoredRoleMembersForRoleIdsWithFilters(Collection<String> roleIds, String principalId, List<String> groupIds, Map<String, String> qualification) {
402            return getRoleMemberBoList(RoleDaoAction.ROLE_MEMBERS_FOR_ROLE_IDS_WITH_FILTERS, roleIds, principalId, groupIds, null, qualification);
403        }
404    
405        /**
406         * Determines whether or not the given role should allow its members to be cached. The default implementation always returns true, but
407         * subclasses can override this method if other non-default Role implementations forbid their members from being cached.
408         *
409         * @param roleId The ID of the role to check for determining whether or not to allow caching of its members.
410         * @return True if the given role allows its members to be cached; false otherwise.
411         */
412        protected boolean shouldCacheMembersOfRole(String roleId) {
413            return true;
414        }
415    
416        protected void addRoleMemberBoToCache(RoleMemberBo roleMember) {
417            if (roleMember != null && shouldCacheMembersOfRole(roleMember.getRoleId())) {
418                getCacheAdministrator().putInCache(getRoleMemberCacheKey(roleMember.getRoleMemberId()), roleMember, ROLE_MEMBER_IMPL_CACHE_GROUP);
419            }
420        }
421    
422        protected RoleMemberBo getRoleMemberFromCache(String roleMemberId) {
423            return (RoleMemberBo) getCacheAdministrator().getFromCache(getRoleMemberCacheKey(roleMemberId));
424        }
425    
426        public void flushInternalRoleMemberCache() {
427            getCacheAdministrator().flushGroup(ROLE_MEMBER_IMPL_CACHE_GROUP);
428        }
429    
430        /**
431         * Retrieves a RoleMemberBo object by its ID. If the role member already exists in the cache, this method will return the cached
432         * version; otherwise, it will retrieve the uncached version from the database and then cache it (if it belongs to a role that allows
433         * its members to be cached) before returning it.
434         */
435        protected RoleMemberBo getRoleMemberBo(String roleMemberId) {
436            if (StringUtils.isBlank(roleMemberId)) {
437                return null;
438            }
439    
440            // If the RoleMemberBo exists in the cache, return the cached one.
441            RoleMemberBo tempRoleMemberBo = getRoleMemberFromCache(roleMemberId);
442            if (tempRoleMemberBo != null) {
443                return tempRoleMemberBo;
444            }
445            // Otherwise, retrieve it normally.
446            tempRoleMemberBo = getBusinessObjectService().findByPrimaryKey(RoleMemberBo.class,
447                    Collections.singletonMap(KIMPropertyConstants.RoleMember.ROLE_MEMBER_ID, roleMemberId));
448            addRoleMemberBoToCache(tempRoleMemberBo);
449            return tempRoleMemberBo;
450        }
451    
452        // -----------------------------------------------------------------------------------------------------------------
453        // Delegation Caching Methods
454        // -----------------------------------------------------------------------------------------------------------------
455    
456        /**
457         * Generates a String key to use for storing or retrieving a DelegateBo to/from the cache.
458         *
459         * @param delegationId The ID of the DelegateBo to generate a key for.
460         * @return A cache key for the DelegateBo with the given ID.
461         */
462        protected String getDelegationCacheKey(String delegationId) {
463            return DELEGATION_IMPL_CACHE_PREFIX + delegationId;
464        }
465    
466        /**
467         * Generates a String key to use for storing or retrieving a List of DelegationBos to/from the cache based on a role's ID.
468         *
469         * @param roleId The ID of the role that the KIM delegations belong to.
470         * @return A cache key for the DelegationBos with the given role ID.
471         */
472        protected String getDelegationListCacheKey(String roleId) {
473            return DELEGATION_IMPL_LIST_CACHE_PREFIX + (StringUtils.isBlank(roleId) ? "" : roleId);
474        }
475    
476        /**
477         * Calls the KimRoleDao's "getDelegationImplMapFromRoleIds" method and/or retrieves any corresponding delegations from the cache.
478         */
479        protected Map<String, DelegateBo> getStoredDelegationImplMapFromRoleIds(Collection<String> roleIds) {
480            Map<String, DelegateBo> finalResults = Collections.emptyMap();
481    
482            if (roleIds != null && !roleIds.isEmpty()) {
483                Map<String, List<DelegateBo>> uncachedLists = new HashMap<String, List<DelegateBo>>();
484                // Retrieve any existing results from the cache.
485                finalResults = getDelegationBoMap(uncachedLists, roleIds);
486    
487                // Retrieve any uncached results from the database and then cache them.
488                if (!uncachedLists.isEmpty()) {
489                    Map<String, DelegateBo> uncachedResults = roleDao.getDelegationImplMapFromRoleIds(
490                            uncachedLists.keySet());
491    
492                    for (Map.Entry<String, DelegateBo> uncachedResult : uncachedResults.entrySet()) {
493                        finalResults.put(uncachedResult.getKey(), uncachedResult.getValue());
494                        addDelegationBoToCache(uncachedResult.getValue());
495                        uncachedLists.get(uncachedResult.getValue().getRoleId()).add(uncachedResult.getValue());
496                    }
497                    for (Map.Entry<String, List<DelegateBo>> uncachedList : uncachedLists.entrySet()) {
498                        getCacheAdministrator().putInCache(getDelegationListCacheKey(uncachedList.getKey()),
499                                uncachedList.getValue(), DELEGATION_IMPL_CACHE_GROUP);
500                    }
501                }
502            }
503    
504            return finalResults;
505        }
506    
507        /**
508         * Calls the KimRoleDao's "getDelegationBosForRoleIds" method and/or retrieves any corresponding delegations from the cache.
509         */
510        protected List<DelegateBo> getStoredDelegationImplsForRoleIds(Collection<String> roleIds) {
511            List<DelegateBo> finalResults = new ArrayList<DelegateBo>();
512    
513            if (roleIds != null && !roleIds.isEmpty()) {
514                Map<String, List<DelegateBo>> uncachedLists = new HashMap<String, List<DelegateBo>>();
515                // Retrieve any existing results from the cache.
516                Map<String, DelegateBo> tempDelegations = getDelegationBoMap(uncachedLists, roleIds);
517                finalResults.addAll(tempDelegations.values());
518    
519                // Retrieve any uncached results from the database and then cache them.
520                if (!uncachedLists.isEmpty()) {
521                    List<DelegateBo> uncachedResults = roleDao.getDelegationBosForRoleIds(uncachedLists.keySet());
522    
523                    for (DelegateBo uncachedResult : uncachedResults) {
524                        addDelegationBoToCache(uncachedResult);
525                        uncachedLists.get(uncachedResult.getRoleId()).add(uncachedResult);
526                    }
527                    for (Map.Entry<String, List<DelegateBo>> uncachedList : uncachedLists.entrySet()) {
528                        getCacheAdministrator().putInCache(getDelegationListCacheKey(uncachedList.getKey()),
529                                uncachedList.getValue(), DELEGATION_IMPL_CACHE_GROUP);
530                    }
531                    finalResults.addAll(uncachedResults);
532                }
533            }
534    
535            return finalResults;
536        }
537    
538        /**
539         * Retrieves any existing delegation lists from the cache for the given role IDs. If the delegations for a given role have not been cached,
540         * then a new entry containing the uncached role ID and an empty List will be added to the given Map.
541         *
542         * @param uncachedLists The Map in which to place any uncached lists; cannot be null.
543         * @param roleIds       The IDs of the roles containing the delegations.
544         * @return A mutable Map containing any existing results from the cache and which maps the delegations' IDs to the delegation objects.
545         * @throws IllegalArgumentException if the provided Map is null.
546         */
547        protected Map<String, DelegateBo> getDelegationBoMap(Map<String, List<DelegateBo>> uncachedLists, Collection<String> roleIds) {
548            if (uncachedLists == null) {
549                throw new IllegalArgumentException("'uncachedLists' parameter cannot be null!");
550            }
551            Map<String, DelegateBo> delegationMap = new HashMap<String, DelegateBo>();
552    
553            // Retrieve any existing results from the cache.
554            if (roleIds != null && !roleIds.isEmpty()) {
555                for (String roleId : roleIds) {
556                    List<DelegateBo> tempDelegates = (List<DelegateBo>) getCacheAdministrator().getFromCache(getDelegationListCacheKey(roleId));
557                    if (tempDelegates != null) {
558                        for (DelegateBo tempDelegate : tempDelegates) {
559                            delegationMap.put(tempDelegate.getDelegationId(), tempDelegate);
560                        }
561                    } else {
562                        uncachedLists.put(roleId, new ArrayList<DelegateBo>());
563                    }
564                }
565            }
566    
567            return delegationMap;
568        }
569    
570        protected void addDelegationBoToCache(DelegateBo delegate) {
571            if (delegate != null) {
572                getCacheAdministrator().putInCache(getDelegationCacheKey(delegate.getDelegationId()),
573                        delegate, DELEGATION_IMPL_CACHE_GROUP);
574            }
575        }
576    
577        protected DelegateBo getDelegationFromCache(String delegationId) {
578            return (DelegateBo) getCacheAdministrator().getFromCache(getDelegationCacheKey(delegationId));
579        }
580    
581        public void flushInternalDelegationCache() {
582            getCacheAdministrator().flushGroup(DELEGATION_IMPL_CACHE_GROUP);
583        }
584    
585        /**
586         * Retrieves a DelegateBo object by its ID. If the delegation already exists in the cache, this method will return the cached
587         * version; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
588         */
589        protected DelegateBo getDelegationBo(String delegationId) {
590            if (StringUtils.isBlank(delegationId)) {
591                return null;
592            }
593    
594            // If the DelegateBo exists in the cache, return the cached one.
595            DelegateBo tempDelegate = getDelegationFromCache(delegationId);
596            if (tempDelegate != null) {
597                return tempDelegate;
598            }
599            // Otherwise, retrieve it normally.
600            tempDelegate = (DelegateBo) getBusinessObjectService().findByPrimaryKey(DelegateBo.class,
601                    Collections.singletonMap(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId));
602            addDelegationBoToCache(tempDelegate);
603            return tempDelegate;
604        }
605    
606        // -----------------------------------------------------------------------------------------------------------------
607        // Delegation Membership Caching Methods
608        // -----------------------------------------------------------------------------------------------------------------
609    
610        /**
611         * Generates a String key to use for storing or retrieving a DelegateMemberBo to/from the cache.
612         *
613         * @param delegationMemberId The ID of the DelegateMemberBo to generate a key for.
614         * @return A cache key for the DelegateMemberBo with the given ID.
615         */
616        protected String getDelegationMemberCacheKey(String delegationMemberId) {
617            return DELEGATION_MEMBER_IMPL_CACHE_PREFIX + delegationMemberId;
618        }
619    
620        /**
621         * Generates a String key to use for storing or retrieving a DelegateMemberBo to/from the cache by both delegation ID and delegation member ID.
622         *
623         * @param delegationId       The ID of the delegation that the DelegateMemberBo belongs to.
624         * @param delegationMemberId The ID of the DelegateMemberBo to generate a key for.
625         * @return A cache key for the DelegateMemberBo with the given delegation ID and delegation member ID.
626         */
627        protected String getDelegationMemberByDelegationAndIdCacheKey(String delegationId, String delegationMemberId) {
628            return new StringBuilder(DELEGATION_MEMBER_IMPL_BY_DLGN_AND_ID_CACHE_PREFIX).append(delegationId).append('-').append(delegationMemberId).toString();
629        }
630    
631        /**
632         * Generates a String key to use for storing or retrieving a DelegateMemberBo List to/from the cache by both delegation ID and member ID.
633         *
634         * @param memberId     The principal/group/role ID of the DelegateMemberBo(s) in the List.
635         * @param delegationId The ID of the delegation that the DelegateMemberBo(s) in the List belong to.
636         * @return A cache key for the DelegateMemberBo List with the given delegation ID and member ID.
637         */
638        protected String getDelegationMemberListByMemberAndDelegationIdCacheKey(String memberId, String delegationId) {
639            return new StringBuilder(DELEGATION_MEMBER_IMPL_LIST_BY_MBR_DLGN_CACHE_PREFIX).append(StringUtils.isBlank(memberId) ? "" : memberId).append(
640                    '-').append(StringUtils.isBlank(delegationId) ? "" : delegationId).toString();
641        }
642    
643        /**
644         * Generates a String key to use for storing or retrieving a List of DelegateMemberBo lists to/from the cache. Some parameters may get
645         * ignored depending on which KimRoleDao call is desired.
646         *
647         * @param daoAction    The RoleDaoAction signifying which KimRoleDao call found this list; will determine how and which parameters are used.
648         * @param delegationId The ID of the DelegateBo that the indicated delegation member belongs to; will be interpreted as an empty String if blank.
649         * @param principalId  The (principal) member ID of the delegation members; will be interpreted as an empty String if blank.
650         * @param groupId      The (group) member ID of the delegation members; will be interpreted as an empty String if blank.
651         * @return A cache key for the DelegateMemberBo List with the given criteria.
652         * @throws IllegalArgumentException if daoAction does not represent a delegation-member-related enumeration value.
653         */
654        protected String getDelegationMemberListCacheKey(RoleDaoAction daoAction, String delegationId, String principalId, String groupId) {
655            switch (daoAction) {
656                case DELEGATION_PRINCIPALS_FOR_PRINCIPAL_ID_AND_DELEGATION_IDS: // Search for principal delegation members.
657                    return new StringBuilder(DELEGATION_MEMBER_IMPL_LIST_CACHE_PREFIX).append(daoAction.DAO_ACTION_CACHE_PREFIX).append(
658                            StringUtils.isBlank(delegationId) ? "" : delegationId).append('-').append(
659                            StringUtils.isBlank(principalId) ? "" : principalId).toString();
660                case DELEGATION_GROUPS_FOR_GROUP_IDS_AND_DELEGATION_IDS: // Search for group delegation members.
661                    return new StringBuilder(DELEGATION_MEMBER_IMPL_LIST_CACHE_PREFIX).append(daoAction.DAO_ACTION_CACHE_PREFIX).append(
662                            StringUtils.isBlank(delegationId) ? "" : delegationId).append('-').append(StringUtils.isBlank(groupId) ? "" : groupId).toString();
663                case DELEGATION_MEMBERS_FOR_DELEGATION_IDS: // Search for delegation members regardless of their member type.
664                    return new StringBuilder(DELEGATION_MEMBER_IMPL_LIST_CACHE_PREFIX).append(daoAction.DAO_ACTION_CACHE_PREFIX).append(
665                            StringUtils.isBlank(delegationId) ? "" : delegationId).toString();
666                default: // daoActionToTake is invalid; throw an exception.
667                    throw new IllegalArgumentException("The 'daoActionToTake' parameter cannot refer to a non-delegation-member-related value!");
668            }
669        }
670    
671        /**
672         * Retrieves a List of delegation members from the cache and/or the KimRoleDao as appropriate.
673         *
674         * @param daoActionToTake An indicator for which KimRoleDao method to use for retrieving uncached results.
675         * @param delegationIds   The IDs of the delegations that the members belong to.
676         * @param principalId     The principal ID of the principal delegation members; may get ignored depending on the RoleDaoAction value.
677         * @param groupIds        The group IDs of the group delegation members; may get ignored depending on the RoleDaoAction value.
678         * @return A List of DelegateMemberBo objects based on the provided parameters.
679         * @throws IllegalArgumentException if daoActionToTake does not represent a delegation-member-list-related enumeration value.
680         */
681        protected List<DelegateMemberBo> getDelegationMemberBoList(RoleDaoAction daoActionToTake, Collection<String> delegationIds,
682                                                                   String principalId, List<String> groupIds) {
683            List<DelegateMemberBo> finalResults = new ArrayList<DelegateMemberBo>();
684            List<String[]> uncachedKeys = new ArrayList<String[]>();
685            Set<String> usedKeys = new HashSet<String>();
686            if (delegationIds == null || delegationIds.isEmpty()) {
687                delegationIds = Collections.singletonList(null);
688            }
689            if (groupIds == null || groupIds.isEmpty()) {
690                groupIds = Collections.singletonList(null);
691            }
692    
693            // Search for cached values based on the intended search action.
694            switch (daoActionToTake) {
695                case DELEGATION_PRINCIPALS_FOR_PRINCIPAL_ID_AND_DELEGATION_IDS: // Search for principal delegation members.
696                    for (String delegationId : delegationIds) {
697                        String tempKey = getDelegationMemberListCacheKey(daoActionToTake, delegationId, principalId, null);
698                        if (!usedKeys.contains(tempKey)) {
699                            List<DelegateMemberBo> tempMembers = (List<DelegateMemberBo>) getCacheAdministrator().getFromCache(tempKey);
700                            if (tempMembers != null) {
701                                finalResults.addAll(tempMembers);
702                            } else {
703                                uncachedKeys.add(new String[]{delegationId, principalId, null});
704                            }
705                            usedKeys.add(tempKey);
706                        }
707                    }
708                    break;
709                case DELEGATION_GROUPS_FOR_GROUP_IDS_AND_DELEGATION_IDS: // Search for group delegation members.
710                    for (String delegationId : delegationIds) {
711                        for (String groupId : groupIds) {
712                            String tempKey = getDelegationMemberListCacheKey(daoActionToTake, delegationId, null, groupId);
713                            if (!usedKeys.contains(tempKey)) {
714                                List<DelegateMemberBo> tempMembers = (List<DelegateMemberBo>) getCacheAdministrator().getFromCache(tempKey);
715                                if (tempMembers != null) {
716                                    finalResults.addAll(tempMembers);
717                                } else {
718                                    uncachedKeys.add(new String[]{delegationId, null, groupId});
719                                }
720                            }
721                        }
722                    }
723                    break;
724                default: // daoActionToTake is invalid; throw an exception.
725                    throw new IllegalArgumentException("The 'daoActionToTake' parameter cannot refer to a non-delegation-member-list-related value!");
726            }
727    
728            // Retrieve any uncached values based on the intended search action.
729            if (!uncachedKeys.isEmpty()) {
730                List<DelegateMemberBo> uncachedResults = new ArrayList<DelegateMemberBo>();
731                Set<String> uncachedDelegationSet = new HashSet<String>();
732                Set<String> uncachedGroupSet = new HashSet<String>();
733                for (String[] uncachedKey : uncachedKeys) {
734                    if (uncachedKey[0] != null) {
735                        uncachedDelegationSet.add(uncachedKey[0]);
736                    }
737                    if (uncachedKey[2] != null) {
738                        uncachedGroupSet.add(uncachedKey[2]);
739                    }
740                }
741                List<String> uncachedDelegations = (uncachedDelegationSet.isEmpty()) ? null : new ArrayList<String>(uncachedDelegationSet);
742                List<String> uncachedGroups = (uncachedGroupSet.isEmpty()) ? null : new ArrayList<String>(uncachedGroupSet);
743                String memberTypeCode = null;
744    
745                // Search for uncached values based on the intended search action.
746                switch (daoActionToTake) {
747                    case DELEGATION_PRINCIPALS_FOR_PRINCIPAL_ID_AND_DELEGATION_IDS: // Search for principal delegation members.
748                        uncachedResults = roleDao.getDelegationPrincipalsForPrincipalIdAndDelegationIds(uncachedDelegations, principalId);
749                        memberTypeCode = Role.PRINCIPAL_MEMBER_TYPE;
750                        break;
751                    case DELEGATION_GROUPS_FOR_GROUP_IDS_AND_DELEGATION_IDS: // Search for group delegation members.
752                        uncachedResults = roleDao.getDelegationGroupsForGroupIdsAndDelegationIds(uncachedDelegations, uncachedGroups);
753                        memberTypeCode = Role.GROUP_MEMBER_TYPE;
754                        break;
755                    default: // This should never happen since the previous switch block should handle this case appropriately.
756                        throw new IllegalArgumentException("The 'daoActionToTake' parameter cannot refer to a non-delegation-member-list-related value!");
757                }
758    
759                // Cache the delegation members and add them to the final results.
760                cacheDelegationMemberLists(daoActionToTake, uncachedKeys, memberTypeCode, uncachedResults);
761                for (DelegateMemberBo uncachedResult : uncachedResults) {
762                    addDelegateMemberBoToCache(uncachedResult);
763                }
764                finalResults.addAll(uncachedResults);
765            }
766    
767            return finalResults;
768        }
769    
770        /**
771         * Caches several Lists of delegation members that are constructed based on the given search parameters.
772         *
773         * @param daoActionToTake The enumeration constant representing the KimRoleDao call that returned the results.
774         * @param uncachedKeys    The keys of the delegation member Lists that will be used to store the uncached results.
775         * @param memberTypeCode  The member type code of all the delegation members in the uncached results.
776         * @param uncachedMembers The uncached delegation members.
777         */
778        private void cacheDelegationMemberLists(RoleDaoAction daoActionToTake, List<String[]> uncachedKeys,
779                                                String memberTypeCode, List<DelegateMemberBo> uncachedMembers) {
780            // Place the uncached delegation members into the list cache appropriately.
781            for (String[] uncachedKey : uncachedKeys) {
782                List<DelegateMemberBo> tempMembers = new ArrayList<DelegateMemberBo>();
783                for (DelegateMemberBo uncachedMember : uncachedMembers) {
784                    if ((memberTypeCode == null || memberTypeCode.equals(uncachedMember.getTypeCode())) &&
785                            (uncachedKey[0] == null || uncachedKey[0].equals(uncachedMember.getDelegationId())) &&
786                            (uncachedKey[1] == null || uncachedKey[1].equals(uncachedMember.getMemberId())) &&
787                            (uncachedKey[2] == null || uncachedKey[2].equals(uncachedMember.getMemberId()))) {
788                        tempMembers.add(uncachedMember);
789                    }
790                }
791                getCacheAdministrator().putInCache(getDelegationMemberListCacheKey(daoActionToTake, uncachedKey[0], uncachedKey[1], uncachedKey[2]),
792                        tempMembers, DELEGATION_MEMBER_IMPL_CACHE_GROUP);
793            }
794        }
795    
796        /**
797         * Calls the KimRoleDao's "getDelegationPrincipalsForPrincipalIdAndDelegationIds" method and/or retrieves any corresponding members from the cache.
798         */
799        protected List<DelegateMemberBo> getStoredDelegationPrincipalsForPrincipalIdAndDelegationIds(Collection<String> delegationIds, String principalId) {
800            return getDelegationMemberBoList(RoleDaoAction.DELEGATION_PRINCIPALS_FOR_PRINCIPAL_ID_AND_DELEGATION_IDS, delegationIds, principalId, null);
801        }
802    
803        /**
804         * Calls the KimRoleDao's "getDelegationGroupsForGroupIdAndDelegationIds" method and/or retrieves any corresponding members from the cache.
805         */
806        protected List<DelegateMemberBo> getStoredDelegationGroupsForGroupIdsAndDelegationIds(Collection<String> delegationIds, List<String> groupIds) {
807            return getDelegationMemberBoList(RoleDaoAction.DELEGATION_GROUPS_FOR_GROUP_IDS_AND_DELEGATION_IDS, delegationIds, null, groupIds);
808        }
809    
810        /**
811         * Calls the KimRoleDao's "getDelegationMembersForDelegationIds" method and/or retrieves any corresponding members from the cache.
812         */
813        protected Map<String, List<DelegateMemberBo>> getStoredDelegationMembersForDelegationIds(List<String> delegationIds) {
814            Map<String, List<DelegateMemberBo>> finalResults = new HashMap<String, List<DelegateMemberBo>>();
815            Set<String> uncachedDelegationIds = new HashSet<String>();
816            boolean idListWasNullOrEmpty = (delegationIds == null || delegationIds.isEmpty());
817            if (idListWasNullOrEmpty) {
818                delegationIds = Collections.singletonList(null);
819            }
820    
821            // Retrieve any existing Lists from the cache.
822            for (String delegationId : delegationIds) {
823                List<DelegateMemberBo> tempMembers = (List<DelegateMemberBo>) getCacheAdministrator().getFromCache(
824                        getDelegationMemberListCacheKey(RoleDaoAction.DELEGATION_MEMBERS_FOR_DELEGATION_IDS, delegationId, null, null));
825                if (tempMembers != null) {
826                    finalResults.put(delegationId, tempMembers);
827                } else {
828                    uncachedDelegationIds.add(delegationId);
829                }
830            }
831    
832            // Retrieve and cache any uncached results. If the initial delegation ID List was null or empty, then also cache a List holding all the results.
833            if (!uncachedDelegationIds.isEmpty()) {
834                List<String> uncachedIdsList = (idListWasNullOrEmpty) ? new ArrayList<String>() : new ArrayList<String>(uncachedDelegationIds);
835    
836                Map<String, List<DelegateMemberBo>> tempMemberMap = roleDao.getDelegationMembersForDelegationIds(uncachedIdsList);
837                List<DelegateMemberBo> allMembers = new ArrayList<DelegateMemberBo>();
838    
839                for (Map.Entry<String, List<DelegateMemberBo>> tempMemberEntry : tempMemberMap.entrySet()) {
840                    getCacheAdministrator().putInCache(getDelegationMemberListCacheKey(RoleDaoAction.DELEGATION_MEMBERS_FOR_DELEGATION_IDS,
841                            tempMemberEntry.getKey(), null, null), tempMemberEntry.getValue(), DELEGATION_MEMBER_IMPL_CACHE_GROUP);
842                    for (DelegateMemberBo tempMember : tempMemberEntry.getValue()) {
843                        addDelegateMemberBoToCache(tempMember);
844                    }
845                    if (idListWasNullOrEmpty) {
846                        allMembers.addAll(tempMemberEntry.getValue());
847                    }
848                    finalResults.put(tempMemberEntry.getKey(), tempMemberEntry.getValue());
849                }
850    
851                if (idListWasNullOrEmpty) {
852                    getCacheAdministrator().putInCache(getDelegationMemberListCacheKey(RoleDaoAction.DELEGATION_MEMBERS_FOR_DELEGATION_IDS,
853                            null, null, null), allMembers, DELEGATION_MEMBER_IMPL_CACHE_GROUP);
854                }
855            }
856    
857            return finalResults;
858        }
859    
860        protected void addDelegateMemberBoToCache(DelegateMemberBo delegateMember) {
861            if (delegateMember != null) {
862                getCacheAdministrator().putInCache(getDelegationMemberCacheKey(delegateMember.getDelegationMemberId()),
863                        delegateMember, DELEGATION_MEMBER_IMPL_CACHE_GROUP);
864                getCacheAdministrator().putInCache(getDelegationMemberByDelegationAndIdCacheKey(
865                        delegateMember.getDelegationId(), delegateMember.getDelegationMemberId()), delegateMember, DELEGATION_MEMBER_IMPL_CACHE_GROUP);
866            }
867        }
868    
869        protected void addDelegationMemberBoListByMemberAndDelegationIdToCache(
870                List<DelegateMemberBo> memberList, String memberId, String delegationId) {
871            if (memberList != null) {
872                getCacheAdministrator().putInCache(getDelegationMemberListByMemberAndDelegationIdCacheKey(memberId, delegationId),
873                        memberList, DELEGATION_MEMBER_IMPL_CACHE_GROUP);
874            }
875        }
876    
877        protected DelegateMemberBo getDelegationMemberFromCache(String delegationMemberId) {
878            return (DelegateMemberBo) getCacheAdministrator().getFromCache(getDelegationMemberCacheKey(delegationMemberId));
879        }
880    
881        protected DelegateMemberBo getDelegationMemberByDelegationAndIdFromCache(String delegationId, String delegationMemberId) {
882            return (DelegateMemberBo) getCacheAdministrator().getFromCache(getDelegationMemberByDelegationAndIdCacheKey(
883                    delegationId, delegationMemberId));
884        }
885    
886        protected List<DelegateMemberBo> getDelegationMemberListByMemberAndDelegationIdFromCache(String memberId, String delegationId) {
887            return (List<DelegateMemberBo>)
888                    getCacheAdministrator().getFromCache(getDelegationMemberListByMemberAndDelegationIdCacheKey(memberId, delegationId));
889        }
890    
891        public void flushInternalDelegationMemberCache() {
892            getCacheAdministrator().flushGroup(DELEGATION_MEMBER_IMPL_CACHE_GROUP);
893        }
894    
895        /**
896         * Retrieves a DelegateMemberBo object by its ID. If the delegation member already exists in the cache, this method will return the cached
897         * version; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
898         */
899        protected DelegateMemberBo getDelegateMemberBo(String delegationMemberId) {
900            if (StringUtils.isBlank(delegationMemberId)) {
901                return null;
902            }
903    
904            // If the DelegateMemberBo exists in the cache, return the cached one.
905            DelegateMemberBo tempDelegateMember = getDelegationMemberFromCache(delegationMemberId);
906            if (tempDelegateMember != null) {
907                return tempDelegateMember;
908            }
909            // Otherwise, retrieve it normally.
910            tempDelegateMember = (DelegateMemberBo) getBusinessObjectService().findByPrimaryKey(DelegateMemberBo.class,
911                    Collections.singletonMap(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMemberId));
912            addDelegateMemberBoToCache(tempDelegateMember);
913            return tempDelegateMember;
914        }
915    
916        /**
917         * Retrieves a DelegateMemberBo object by its ID and the ID of the delegation it belongs to. If the delegation member exists in the cache,
918         * this method will return the cached one; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
919         */
920        protected DelegateMemberBo getDelegationMemberBoByDelegationAndId(String delegationId, String delegationMemberId) {
921            if (StringUtils.isBlank(delegationId) || StringUtils.isBlank(delegationMemberId)) {
922                return null;
923            }
924    
925            // If the DelegateMemberBo exists in the cache, return the cached one.
926            DelegateMemberBo tempDelegateMember = getDelegationMemberByDelegationAndIdFromCache(delegationId, delegationMemberId);
927            if (tempDelegateMember != null) {
928                return tempDelegateMember;
929            }
930            // Otherwise, retrieve it normally.
931            Map<String, String> searchCriteria = new HashMap<String, String>();
932            searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId);
933            searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_MEMBER_ID, delegationMemberId);
934            List<DelegateMemberBo> memberList =
935                    (List<DelegateMemberBo>) getBusinessObjectService().findMatching(DelegateMemberBo.class, searchCriteria);
936            if (memberList != null && !memberList.isEmpty()) {
937                tempDelegateMember = memberList.get(0);
938                addDelegateMemberBoToCache(tempDelegateMember);
939            }
940            return tempDelegateMember;
941        }
942    
943        /**
944         * Retrieves a DelegateMemberBo List by (principal/group/role) member ID and delegation ID. If the List already exists in the cache,
945         * this method will return the cached one; otherwise, it will retrieve the uncached version from the database and then cache it before returning it.
946         */
947        protected List<DelegateMemberBo> getDelegationMemberBoListByMemberAndDelegationId(String memberId, String delegationId) {
948            // If the DelegateMemberBo List exists in the cache, return the cached one.
949            List<DelegateMemberBo> memberList = getDelegationMemberListByMemberAndDelegationIdFromCache(memberId, delegationId);
950            if (memberList != null) {
951                return memberList;
952            }
953    
954            // Otherwise, retrieve it normally.
955            Map<String, String> searchCriteria = new HashMap<String, String>();
956            searchCriteria.put(KimConstants.PrimaryKeyConstants.MEMBER_ID, memberId);
957            searchCriteria.put(KimConstants.PrimaryKeyConstants.DELEGATION_ID, delegationId);
958            List<DelegateMemberBo> tempList =
959                    (List<DelegateMemberBo>) getBusinessObjectService().findMatching(DelegateMemberBo.class, searchCriteria);
960            if (tempList != null && !tempList.isEmpty()) {
961                memberList = new ArrayList<DelegateMemberBo>();
962                memberList.addAll(tempList);
963                addDelegationMemberBoListByMemberAndDelegationIdToCache(memberList, memberId, delegationId);
964            }
965            return memberList;
966        }
967    
968        public void flushInternalRoleCache() {
969            getCacheAdministrator().flushGroup(ROLE_IMPL_CACHE_GROUP);
970        }
971    
972        public RoleMember findRoleMember(String roleMemberId) {
973            Map<String, String> fieldValues = new HashMap<String, String>();
974            fieldValues.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMemberId);
975            List<RoleMember> roleMembers = findRoleMembers(fieldValues);
976            if (roleMembers != null && roleMembers.size() > 0) {
977                return roleMembers.get(0);
978            }
979            return null;
980        }
981    
982        public List<RoleMember> findRoleMembers(Map<String, String> fieldValues) {
983            List<RoleMember> roleMembers = new ArrayList<RoleMember>();
984            List<RoleMemberBo> roleMemberBos = (List<RoleMemberBo>) getLookupService().findCollectionBySearchHelper(
985                    RoleMemberBo.class, fieldValues, true);
986    
987            for (RoleMemberBo bo : roleMemberBos) {
988                RoleMember roleMember = RoleMemberBo.to(bo);
989                roleMembers.add(roleMember);
990            }
991            return roleMembers;
992        }
993    
994        public List<RoleResponsibilityAction> getRoleMemberResponsibilityActions(String roleMemberId) {
995            Map<String, String> criteria = new HashMap<String, String>(1);
996            criteria.put(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, roleMemberId);
997    
998            List<RoleResponsibilityActionBo> responsibilityActionBoList = (List<RoleResponsibilityActionBo>)
999                    getBusinessObjectService().findMatching(RoleResponsibilityActionBo.class, criteria);
1000    
1001            List<RoleResponsibilityAction> roleResponsibilityActionsList = new ArrayList<RoleResponsibilityAction>();
1002            for (RoleResponsibilityActionBo roleResponsibilityActionBo : responsibilityActionBoList) {
1003                RoleResponsibilityAction roleResponsibility = RoleResponsibilityActionBo.to(roleResponsibilityActionBo);
1004                roleResponsibilityActionsList.add(roleResponsibility);
1005            }
1006            return roleResponsibilityActionsList;
1007        }
1008    
1009        public List<DelegateMember> findDelegateMembers(final Map<String, String> fieldValues) {
1010            List<DelegateMember> delegateMembers = new ArrayList<DelegateMember>();
1011            List<DelegateBo> delegateBoList = (List<DelegateBo>) getLookupService().findCollectionBySearchHelper(
1012                    DelegateBo.class, fieldValues, true);
1013    
1014            if (delegateBoList != null && !delegateBoList.isEmpty()) {
1015                Map<String, String> delegationMemberFieldValues = new HashMap<String, String>();
1016                for (String key : fieldValues.keySet()) {
1017                    if (key.startsWith(KimConstants.KimUIConstants.MEMBER_ID_PREFIX)) {
1018                        delegationMemberFieldValues.put(
1019                                key.substring(key.indexOf(
1020                                        KimConstants.KimUIConstants.MEMBER_ID_PREFIX) + KimConstants.KimUIConstants.MEMBER_ID_PREFIX.length()),
1021                                fieldValues.get(key));
1022                    }
1023                }
1024    
1025                StringBuffer memberQueryString = new StringBuffer();
1026                for (DelegateBo delegate : delegateBoList) {
1027                    memberQueryString.append(delegate.getDelegationId() + KimConstants.KimUIConstants.OR_OPERATOR);
1028                }
1029                delegationMemberFieldValues.put(KimConstants.PrimaryKeyConstants.DELEGATION_ID,
1030                        StringUtils.stripEnd(memberQueryString.toString(), KimConstants.KimUIConstants.OR_OPERATOR));
1031                List<DelegateMemberBo> delegateMemberBoList = (List<DelegateMemberBo>) getLookupService().findCollectionBySearchHelper(
1032                        DelegateMemberBo.class, delegationMemberFieldValues, true);
1033    
1034    
1035                for (DelegateMemberBo delegateMemberBo : delegateMemberBoList) {
1036                    DelegateMember delegateMember = DelegateMemberBo.to(delegateMemberBo);
1037                    delegateMembers.add(delegateMember);
1038                }
1039            }
1040            return delegateMembers;
1041        }
1042    
1043        protected DelegateBo getDelegationImpl(List<DelegateBo> delegates, String delegationId) {
1044            if (StringUtils.isEmpty(delegationId) || delegates == null) {
1045                return null;
1046            }
1047            for (DelegateBo delegate : delegates) {
1048                if (StringUtils.equals(delegate.getDelegationId(), delegationId)) {
1049                    return delegate;
1050                }
1051            }
1052            return null;
1053        }
1054    
1055        protected Object getMember(String memberTypeCode, String memberId) {
1056            if (StringUtils.isBlank(memberId)) {
1057                return null;
1058            }
1059            if (KimConstants.KimUIConstants.MEMBER_TYPE_PRINCIPAL_CODE.equals(memberTypeCode)) {
1060                return getIdentityService().getPrincipal(memberId);
1061            } else if (KimConstants.KimUIConstants.MEMBER_TYPE_GROUP_CODE.equals(memberTypeCode)) {
1062                return getGroupService().getGroup(memberId);
1063            } else if (KimConstants.KimUIConstants.MEMBER_TYPE_ROLE_CODE.equals(memberTypeCode)) {
1064                return getRoleBo(memberId);
1065            }
1066            return null;
1067        }
1068    
1069        protected String getMemberName(Object member) {
1070            if (member == null) {
1071                return "";
1072            }
1073            if (member instanceof Principal) {
1074                return ((Principal) member).getPrincipalName();
1075            }
1076            if (member instanceof Group) {
1077                return ((Group) member).getName();
1078            }
1079            if (member instanceof Role) {
1080                return ((Role) member).getName();
1081            }
1082            return member.toString();
1083        }
1084    
1085        protected String getMemberNamespaceCode(Object member) {
1086            if (member == null) {
1087                return "";
1088            }
1089            if (member instanceof Principal) {
1090                return "";
1091            }
1092            if (member instanceof Group) {
1093                return ((Group) member).getNamespaceCode();
1094            }
1095            if (member instanceof Role) {
1096                return ((Role) member).getNamespaceCode();
1097            }
1098            return "";
1099        }
1100    
1101        protected RoleBo getRoleBo(String roleId) {
1102            if (StringUtils.isBlank(roleId)) {
1103                return null;
1104            }
1105            // check for a non-null result in the cache, return it if found
1106            RoleBo cachedResult = getRoleFromCache(roleId);
1107            if (cachedResult != null) {
1108                return cachedResult;
1109            }
1110            // otherwise, run the query
1111            RoleBo result = (RoleBo) getBusinessObjectService().findBySinglePrimaryKey(RoleBo.class, roleId);
1112            addRoleBoToCache(result);
1113            return result;
1114        }
1115    
1116        protected DelegateBo getDelegationOfType(String roleId, String delegationTypeCode) {
1117            List<DelegateBo> roleDelegates = getRoleDelegations(roleId);
1118            if (isDelegationPrimary(delegationTypeCode)) {
1119                return getPrimaryDelegation(roleId, roleDelegates);
1120            } else {
1121                return getSecondaryDelegation(roleId, roleDelegates);
1122            }
1123        }
1124    
1125        private DelegateBo getSecondaryDelegation(String roleId, List<DelegateBo> roleDelegates) {
1126            DelegateBo secondaryDelegate = null;
1127            RoleBo roleBo = getRoleBo(roleId);
1128            for (DelegateBo delegate : roleDelegates) {
1129                if (isDelegationSecondary(delegate.getDelegationTypeCode())) {
1130                    secondaryDelegate = delegate;
1131                }
1132            }
1133            if (secondaryDelegate == null) {
1134                secondaryDelegate = new DelegateBo();
1135                secondaryDelegate.setRoleId(roleId);
1136                secondaryDelegate.setDelegationId(getNewDelegationId());
1137                secondaryDelegate.setDelegationTypeCode(DelegationType.PRIMARY.getCode());
1138                secondaryDelegate.setKimTypeId(roleBo.getKimTypeId());
1139            }
1140            return secondaryDelegate;
1141        }
1142    
1143        protected DelegateBo getPrimaryDelegation(String roleId, List<DelegateBo> roleDelegates) {
1144            DelegateBo primaryDelegate = null;
1145            RoleBo roleBo = getRoleBo(roleId);
1146            for (DelegateBo delegate : roleDelegates) {
1147                if (isDelegationPrimary(delegate.getDelegationTypeCode())) {
1148                    primaryDelegate = delegate;
1149                }
1150            }
1151            if (primaryDelegate == null) {
1152                primaryDelegate = new DelegateBo();
1153                primaryDelegate.setRoleId(roleId);
1154                primaryDelegate.setDelegationId(getNewDelegationId());
1155                primaryDelegate.setDelegationTypeCode(DelegationType.PRIMARY.getCode());
1156                primaryDelegate.setKimTypeId(roleBo.getKimTypeId());
1157            }
1158            return primaryDelegate;
1159        }
1160    
1161        protected RoleMemberBo matchingMemberRecord(List<RoleMemberBo> roleMembers, String memberId, String memberTypeCode, Map<String, String> qualifier) {
1162            for (RoleMemberBo rm : roleMembers) {
1163                if (doesMemberMatch(rm, memberId, memberTypeCode, qualifier)) {
1164                    return rm;
1165                }
1166            }
1167            return null;
1168        }
1169    
1170        protected boolean isDelegationPrimary(String delegationTypeCode) {
1171            return DelegationType.PRIMARY.getCode().equals(delegationTypeCode);
1172        }
1173    
1174        protected boolean isDelegationSecondary(String delegationTypeCode) {
1175            return DelegationType.PRIMARY.getCode().equals(delegationTypeCode);
1176        }
1177    
1178    
1179        private List<DelegateBo> getRoleDelegations(String roleId) {
1180            if (roleId == null) {
1181                return new ArrayList<DelegateBo>();
1182            }
1183            return getStoredDelegationImplsForRoleIds(Collections.singletonList(roleId));
1184    
1185        }
1186    
1187        protected RoleBo getRoleBoByName(String namespaceCode, String roleName) {
1188            if (StringUtils.isBlank(namespaceCode)
1189                    || StringUtils.isBlank(roleName)) {
1190                return null;
1191            }
1192            // check for a non-null result in the cache, return it if found
1193            RoleBo cachedResult = getRoleFromCache(namespaceCode, roleName);
1194            if (cachedResult != null) {
1195                return cachedResult;
1196            }
1197            Map<String, String> criteria = new HashMap<String, String>();
1198            criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode);
1199            criteria.put(KimConstants.UniqueKeyConstants.NAME, roleName);
1200            criteria.put(KRADPropertyConstants.ACTIVE, "Y");
1201            // while this is not actually the primary key - there will be at most one row with these criteria
1202            RoleBo result = getBusinessObjectService().findByPrimaryKey(RoleBo.class, criteria);
1203            addRoleBoToCache(result);
1204            return result;
1205        }
1206    
1207        protected boolean doAnyMemberRecordsMatch(List<RoleMemberBo> roleMembers, String memberId, String memberTypeCode, Map<String, String> qualifier) {
1208            for (RoleMemberBo rm : roleMembers) {
1209                if (doesMemberMatch(rm, memberId, memberTypeCode, qualifier)) {
1210                    return true;
1211                }
1212            }
1213            return false;
1214        }
1215    
1216        protected boolean doesMemberMatch(RoleMemberBo roleMember, String memberId, String memberTypeCode, Map<String, String> qualifier) {
1217            if (roleMember.getMemberId().equals(memberId) && roleMember.getMemberTypeCode().equals(memberTypeCode)) {
1218                // member ID/type match
1219                Map<String, String> roleQualifier = roleMember.getAttributes();
1220                if ((qualifier == null || qualifier.isEmpty())
1221                        && (roleQualifier == null || roleQualifier.isEmpty())) {
1222                    return true; // blank qualifier match
1223                } else {
1224                    if (qualifier != null && roleQualifier != null && qualifier.equals(roleQualifier)) {
1225                        return true; // qualifier match
1226                    }
1227                }
1228            }
1229            return false;
1230        }
1231    
1232        /**
1233         * This method tests to see if assigning a roleBo to another roleBo will create a circular reference.
1234         * The Role is checked to see if it is a member (direct or nested) of the roleBo to be assigned as a member.
1235         *
1236         * @param newMemberId
1237         * @param roleBo
1238         * @return true  - assignment is allowed, no circular reference will be created.
1239         *         false - illegal assignment, it will create a circular membership
1240         */
1241        protected boolean checkForCircularRoleMembership(String newMemberId, RoleBo roleBo) {
1242            // get all nested roleBo members that are of type roleBo
1243            Set<String> newRoleMemberIds = getRoleTypeRoleMemberIds(newMemberId);
1244            if (newRoleMemberIds.contains(roleBo.getId())) {
1245                return false;
1246            }
1247            return true;
1248        }
1249    
1250        // TODO: pulling attribute IDs repeatedly is inefficient - consider caching the entire list as a map
1251        @SuppressWarnings("unchecked")
1252        protected String getKimAttributeId(String attributeName) {
1253            String result = null;
1254            Map<String, Object> critieria = new HashMap<String, Object>(1);
1255            critieria.put("attributeName", attributeName);
1256            Collection<KimAttributeBo> defs = getBusinessObjectService().findMatching(KimAttributeBo.class, critieria);
1257            if (CollectionUtils.isNotEmpty(defs)) {
1258                result = defs.iterator().next().getId();
1259            }
1260            return result;
1261        }
1262    
1263        /**
1264         * @return the applicationRoleTypeCache
1265         */
1266        protected Map<String, Boolean> getApplicationRoleTypeCache() {
1267            return this.applicationRoleTypeCache;
1268        }
1269    
1270        /**
1271         * @return the roleTypeServiceCache
1272         */
1273        protected Map<String, KimRoleTypeService> getRoleTypeServiceCache() {
1274            return this.roleTypeServiceCache;
1275        }
1276    
1277        /**
1278         * @return the delegationTypeServiceCache
1279         */
1280        protected Map<String, KimDelegationTypeService> getDelegationTypeServiceCache() {
1281            return this.delegationTypeServiceCache;
1282        }
1283    
1284        protected String getRoleCacheKey(String roleId) {
1285            return ROLE_IMPL_CACHE_PREFIX + roleId;
1286        }
1287    
1288        protected String getRoleByNameCacheKey(String namespaceCode, String roleName) {
1289            return ROLE_IMPL_BY_NAME_CACHE_PREFIX + namespaceCode + "-" + roleName;
1290        }
1291    
1292        protected void addRoleBoToCache(RoleBo roleBo) {
1293            if (roleBo != null) {
1294                getCacheAdministrator().putInCache(getRoleCacheKey(roleBo.getId()), roleBo, ROLE_IMPL_CACHE_GROUP);
1295                getCacheAdministrator().putInCache(getRoleByNameCacheKey(roleBo.getNamespaceCode(), roleBo.getName()), roleBo, ROLE_IMPL_CACHE_GROUP);
1296            }
1297        }
1298    
1299        protected RoleBo getRoleFromCache(String roleId) {
1300            return (RoleBo) getCacheAdministrator().getFromCache(getRoleCacheKey(roleId));
1301        }
1302    
1303        protected RoleBo getRoleFromCache(String namespaceCode, String roleName) {
1304            return (RoleBo) getCacheAdministrator().getFromCache(getRoleByNameCacheKey(namespaceCode, roleName));
1305        }
1306    
1307        protected String getNewDelegationId() {
1308            SequenceAccessorService sas = getSequenceAccessorService();
1309            Long nextSeq = sas.getNextAvailableSequenceNumber(
1310                    KimConstants.SequenceNames.KRIM_DLGN_ID_S,
1311                    DelegateBo.class);
1312            return nextSeq.toString();
1313        }
1314    
1315        protected String getNewAttributeDataId() {
1316            SequenceAccessorService sas = getSequenceAccessorService();
1317            Long nextSeq = sas.getNextAvailableSequenceNumber(
1318                    KimConstants.SequenceNames.KRIM_ATTR_DATA_ID_S,
1319                    RoleMemberAttributeDataBo.class);
1320            return nextSeq.toString();
1321        }
1322    
1323        protected String getNewDelegationMemberId() {
1324            SequenceAccessorService sas = getSequenceAccessorService();
1325            Long nextSeq = sas.getNextAvailableSequenceNumber(
1326                    KimConstants.SequenceNames.KRIM_DLGN_MBR_ID_S,
1327                    DelegateBo.class);
1328            return nextSeq.toString();
1329        }
1330    
1331        protected BusinessObjectService getBusinessObjectService() {
1332            if (businessObjectService == null) {
1333                businessObjectService = KRADServiceLocator.getBusinessObjectService();
1334            }
1335            return businessObjectService;
1336        }
1337    
1338        /**
1339         * @return the lookupService
1340         */
1341        protected LookupService getLookupService() {
1342            if (lookupService == null) {
1343                lookupService = KRADServiceLocatorWeb.getLookupService();
1344            }
1345            return lookupService;
1346        }
1347    
1348        protected RiceCacheAdministrator getCacheAdministrator() {
1349            if (cacheAdministrator == null) {
1350                cacheAdministrator = KsbApiServiceLocator.getCacheAdministrator();
1351            }
1352            return cacheAdministrator;
1353        }
1354    
1355        protected IdentityService getIdentityService() {
1356            if (identityService == null) {
1357                identityService = KimApiServiceLocator.getIdentityService();
1358            }
1359    
1360            return identityService;
1361        }
1362        
1363        protected GroupService getGroupService() {
1364            if (groupService == null) {
1365                groupService = KimApiServiceLocator.getGroupService();
1366            }
1367    
1368            return groupService;
1369        }
1370    
1371        protected SequenceAccessorService getSequenceAccessorService() {
1372            if (sequenceAccessorService == null) {
1373                sequenceAccessorService = KRADServiceLocator.getSequenceAccessorService();
1374            }
1375            return sequenceAccessorService;
1376        }
1377    
1378        protected ResponsibilityInternalService getResponsibilityInternalService() {
1379            if (responsibilityInternalService == null) {
1380                responsibilityInternalService = KIMServiceLocatorInternal.getResponsibilityInternalService();
1381            }
1382            return responsibilityInternalService;
1383        }
1384    
1385        protected IdentityManagementNotificationService getIdentityManagementNotificationService() {
1386            return (IdentityManagementNotificationService) KsbApiServiceLocator.getMessageHelper().getServiceAsynchronously(new QName("KIM", "kimIdentityManagementNotificationService"));
1387        }
1388    
1389        /**
1390         * An internal helper class for encapsulating the information related to generating a key for a RoleMemberBo list.
1391         *
1392         * @author Kuali Rice Team (rice.collab@kuali.org)
1393         */
1394        private class RoleMemberCacheKeyHelper {
1395            private final RoleDaoAction ROLE_DAO_ACTION;
1396            private final String ROLE_ID;
1397            private final String PRINCIPAL_ID;
1398            private final String GROUP_ID;
1399            private final String MEMBER_TYPE_CODE;
1400            private String cacheKey;
1401    
1402            private RoleMemberCacheKeyHelper(RoleDaoAction roleDaoAction, String roleId, String principalId, String groupId, String memberTypeCode) {
1403                this.ROLE_DAO_ACTION = roleDaoAction;
1404                this.ROLE_ID = roleId;
1405                this.PRINCIPAL_ID = principalId;
1406                this.GROUP_ID = groupId;
1407                this.MEMBER_TYPE_CODE = memberTypeCode;
1408            }
1409    
1410            private String getCacheKey() {
1411                if (this.cacheKey == null) {
1412                    this.cacheKey = getRoleMemberListCacheKey(ROLE_DAO_ACTION, ROLE_ID, PRINCIPAL_ID, GROUP_ID, MEMBER_TYPE_CODE);
1413                }
1414                return this.cacheKey;
1415            }
1416        }
1417    
1418        /**
1419         * @return the roleDao
1420         */
1421        public RoleDao getRoleDao() {
1422            return this.roleDao;
1423        }
1424    
1425        /**
1426         * @param roleDao the roleDao to set
1427         */
1428        public void setRoleDao(RoleDao roleDao) {
1429            this.roleDao = roleDao;
1430        }
1431    
1432    }