001    /*
002     * Copyright 2008-2009 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kim.service.impl;
017    
018    import java.util.ArrayList;
019    import java.util.Collections;
020    import java.util.HashMap;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    
025    import javax.jws.WebService;
026    import javax.servlet.http.HttpServletRequest;
027    
028    import org.apache.log4j.Logger;
029    import org.kuali.rice.core.util.MaxAgeSoftReference;
030    import org.kuali.rice.core.util.MaxSizeMap;
031    import org.kuali.rice.core.util.RiceDebugUtils;
032    import org.kuali.rice.kim.bo.entity.KimEntity;
033    import org.kuali.rice.kim.bo.entity.KimPrincipal;
034    import org.kuali.rice.kim.bo.entity.dto.KimEntityDefaultInfo;
035    import org.kuali.rice.kim.bo.entity.dto.KimEntityInfo;
036    import org.kuali.rice.kim.bo.entity.dto.KimPrincipalInfo;
037    import org.kuali.rice.kim.bo.group.dto.GroupInfo;
038    import org.kuali.rice.kim.bo.reference.dto.AddressTypeInfo;
039    import org.kuali.rice.kim.bo.reference.dto.AffiliationTypeInfo;
040    import org.kuali.rice.kim.bo.reference.dto.CitizenshipStatusInfo;
041    import org.kuali.rice.kim.bo.reference.dto.EmailTypeInfo;
042    import org.kuali.rice.kim.bo.reference.dto.EmploymentStatusInfo;
043    import org.kuali.rice.kim.bo.reference.dto.EmploymentTypeInfo;
044    import org.kuali.rice.kim.bo.reference.dto.EntityNameTypeInfo;
045    import org.kuali.rice.kim.bo.reference.dto.EntityTypeInfo;
046    import org.kuali.rice.kim.bo.reference.dto.ExternalIdentifierTypeInfo;
047    import org.kuali.rice.kim.bo.reference.dto.KimCodeInfoBase;
048    import org.kuali.rice.kim.bo.reference.dto.PhoneTypeInfo;
049    import org.kuali.rice.kim.bo.role.dto.KimPermissionInfo;
050    import org.kuali.rice.kim.bo.role.dto.KimResponsibilityInfo;
051    import org.kuali.rice.kim.bo.role.dto.PermissionAssigneeInfo;
052    import org.kuali.rice.kim.bo.role.dto.ResponsibilityActionInfo;
053    import org.kuali.rice.kim.bo.types.dto.AttributeSet;
054    import org.kuali.rice.kim.service.AuthenticationService;
055    import org.kuali.rice.kim.service.GroupService;
056    import org.kuali.rice.kim.service.GroupUpdateService;
057    import org.kuali.rice.kim.service.IdentityManagementService;
058    import org.kuali.rice.kim.service.IdentityService;
059    import org.kuali.rice.kim.service.IdentityUpdateService;
060    import org.kuali.rice.kim.service.KIMServiceLocator;
061    import org.kuali.rice.kim.service.PermissionService;
062    import org.kuali.rice.kim.service.ResponsibilityService;
063    import org.kuali.rice.kim.util.KIMWebServiceConstants;
064    import org.springframework.beans.factory.InitializingBean;
065    import org.springframework.transaction.annotation.Transactional;
066    
067    @WebService(endpointInterface = KIMWebServiceConstants.IdentityManagementService.INTERFACE_CLASS, serviceName = KIMWebServiceConstants.IdentityManagementService.WEB_SERVICE_NAME, portName = KIMWebServiceConstants.IdentityManagementService.WEB_SERVICE_PORT, targetNamespace = KIMWebServiceConstants.MODULE_TARGET_NAMESPACE)
068    public class IdentityManagementServiceImpl implements IdentityManagementService, InitializingBean {
069            private static final Logger LOG = Logger.getLogger( IdentityManagementServiceImpl.class );
070    
071            private AuthenticationService authenticationService;
072            private PermissionService permissionService;
073            private ResponsibilityService responsibilityService;
074            private IdentityService identityService;
075            private GroupService groupService;
076            private GroupUpdateService groupUpdateService;
077            private IdentityUpdateService identityUpdateService;
078    
079    
080            // Max age defined in seconds
081            protected int entityPrincipalCacheMaxSize = 200;
082            protected int entityPrincipalCacheMaxAgeSeconds = 30;
083            protected int groupCacheMaxSize = 200;
084            protected int groupCacheMaxAgeSeconds = 30;
085            protected int permissionCacheMaxSize = 200;
086            protected int permissionCacheMaxAgeSeconds = 30;
087            protected int responsibilityCacheMaxSize = 200;
088            protected int responsibilityCacheMaxAgeSeconds = 30;
089    
090            protected Map<String,MaxAgeSoftReference<KimEntityDefaultInfo>> entityDefaultInfoCache;
091            protected Map<String,MaxAgeSoftReference<KimEntity>> entityCache;
092            protected Map<String,MaxAgeSoftReference<KimEntityInfo>> entityInfoCache;
093            protected Map<String,MaxAgeSoftReference<KimPrincipalInfo>> principalByIdCache;
094            protected Map<String,MaxAgeSoftReference<KimPrincipalInfo>> principalByNameCache;
095            protected Map<String,MaxAgeSoftReference<GroupInfo>> groupByIdCache;
096            protected Map<String,MaxAgeSoftReference<GroupInfo>> groupByNameCache;
097            protected Map<String,MaxAgeSoftReference<List<String>>> groupIdsForPrincipalCache;
098            protected Map<String,MaxAgeSoftReference<List<? extends GroupInfo>>> groupsForPrincipalCache;
099            protected Map<String,MaxAgeSoftReference<Boolean>> isMemberOfGroupCache;
100            protected Map<String,MaxAgeSoftReference<Boolean>> isGroupMemberOfGroupCache;
101            protected Map<String,MaxAgeSoftReference<List<String>>> groupMemberPrincipalIdsCache;
102            protected Map<String,MaxAgeSoftReference<Boolean>> hasPermissionCache;
103            protected Map<String,MaxAgeSoftReference<Boolean>> hasPermissionByTemplateCache;
104            protected Map<String,MaxAgeSoftReference<Boolean>> isAuthorizedCache;
105            protected Map<String,MaxAgeSoftReference<Boolean>> isAuthorizedByTemplateNameCache;
106        protected Map<String,MaxAgeSoftReference<Boolean>> isPermissionDefinedForTemplateNameCache;
107    
108        protected HashMap<String,KimCodeInfoBase> kimReferenceTypeCache = new HashMap<String, KimCodeInfoBase>();
109    
110            public void afterPropertiesSet() throws Exception {
111                    entityDefaultInfoCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<KimEntityDefaultInfo>>( entityPrincipalCacheMaxSize ) );
112                    entityCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<KimEntity>>( entityPrincipalCacheMaxSize ) );
113                    entityInfoCache = Collections.synchronizedMap( new MaxSizeMap<String, MaxAgeSoftReference<KimEntityInfo>>(entityPrincipalCacheMaxSize));
114                    principalByIdCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<KimPrincipalInfo>>( entityPrincipalCacheMaxSize ) );
115                    principalByNameCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<KimPrincipalInfo>>( entityPrincipalCacheMaxSize ) );
116                    groupByIdCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<GroupInfo>>( groupCacheMaxSize ) );
117                    groupByNameCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<GroupInfo>>( groupCacheMaxSize ) );
118                    groupIdsForPrincipalCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<List<String>>>( groupCacheMaxSize ) );
119                    groupsForPrincipalCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<List<? extends GroupInfo>>>( groupCacheMaxSize ) );
120                    isMemberOfGroupCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( groupCacheMaxSize ) );
121                    groupMemberPrincipalIdsCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<List<String>>>( groupCacheMaxSize ) );
122                    hasPermissionCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( permissionCacheMaxSize ) );
123                    hasPermissionByTemplateCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( permissionCacheMaxSize ) );
124                    isPermissionDefinedForTemplateNameCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( permissionCacheMaxSize ) );
125                    isAuthorizedByTemplateNameCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( permissionCacheMaxSize ) );
126                    isAuthorizedCache = Collections.synchronizedMap( new MaxSizeMap<String,MaxAgeSoftReference<Boolean>>( permissionCacheMaxSize ) );
127            }
128    
129            public void flushAllCaches() {
130                    flushEntityPrincipalCaches();
131                    flushGroupCaches();
132                    flushPermissionCaches();
133                    flushResponsibilityCaches();
134            }
135    
136            public void flushEntityPrincipalCaches() {
137                    entityDefaultInfoCache.clear();
138                    entityCache.clear();
139                    principalByIdCache.clear();
140                    principalByNameCache.clear();
141            }
142    
143            public void flushGroupCaches() {
144                    groupByIdCache.clear();
145                    groupByNameCache.clear();
146                    groupIdsForPrincipalCache.clear();
147                    groupsForPrincipalCache.clear();
148                    isMemberOfGroupCache.clear();
149                    groupMemberPrincipalIdsCache.clear();
150            }
151    
152            public void flushPermissionCaches() {
153                    hasPermissionCache.clear();
154                    hasPermissionByTemplateCache.clear();
155                    isPermissionDefinedForTemplateNameCache.clear();
156                    isAuthorizedByTemplateNameCache.clear();
157                    isAuthorizedCache.clear();
158            }
159    
160            public void flushResponsibilityCaches() {
161                    // nothing currently being cached
162            }
163    
164            protected KimEntityDefaultInfo getEntityDefaultInfoFromCache( String entityId ) {
165                    MaxAgeSoftReference<KimEntityDefaultInfo> entityRef = entityDefaultInfoCache.get( "entityId="+entityId );
166                    if ( entityRef != null ) {
167                            return entityRef.get();
168                    }
169                    return null;
170            }
171    
172            protected KimEntityDefaultInfo getEntityDefaultInfoFromCacheByPrincipalId( String principalId ) {
173                    MaxAgeSoftReference<KimEntityDefaultInfo> entityRef = entityDefaultInfoCache.get( "principalId="+principalId );
174                    if ( entityRef != null ) {
175                            return entityRef.get();
176                    }
177                    return null;
178            }
179    
180            protected KimEntityDefaultInfo getEntityDefaultInfoFromCacheByPrincipalName( String principalName ) {
181                    MaxAgeSoftReference<KimEntityDefaultInfo> entityRef = entityDefaultInfoCache.get( "principalName="+principalName );
182                    if ( entityRef != null ) {
183                            return entityRef.get();
184                    }
185                    return null;
186            }
187    
188            protected KimEntityInfo getEntityInfoFromCache( String entityId ) {
189                    MaxAgeSoftReference<KimEntityInfo> entityRef = entityInfoCache.get( "entityId="+entityId );
190                    if ( entityRef != null ) {
191                            return entityRef.get();
192                    }
193                    return null;
194            }
195    
196            protected KimEntityInfo getEntityInfoFromCacheByPrincipalId( String principalId ) {
197                    MaxAgeSoftReference<KimEntityInfo> entityRef = entityInfoCache.get( "principalId="+principalId );
198                    if ( entityRef != null ) {
199                            return entityRef.get();
200                    }
201                    return null;
202            }
203    
204            protected KimEntityInfo getEntityInfoFromCacheByPrincipalName( String principalName ) {
205                    MaxAgeSoftReference<KimEntityInfo> entityRef = entityInfoCache.get( "principalName="+principalName );
206                    if ( entityRef != null ) {
207                            return entityRef.get();
208                    }
209                    return null;
210            }
211    
212            protected KimEntity getEntityFromCache( String entityId ) {
213                    MaxAgeSoftReference<KimEntity> entityRef = entityCache.get( "entityId="+entityId );
214                    if ( entityRef != null ) {
215                            return entityRef.get();
216                    }
217                    return null;
218            }
219    
220            protected KimEntity getEntityFromCacheByPrincipalId( String principalId ) {
221                    MaxAgeSoftReference<KimEntity> entityRef = entityCache.get( "principalId="+principalId );
222                    if ( entityRef != null ) {
223                            return entityRef.get();
224                    }
225                    return null;
226            }
227    
228            protected KimEntity getEntityFromCacheByPrincipalName( String principalName ) {
229                    MaxAgeSoftReference<KimEntity> entityRef = entityCache.get( "principalName="+principalName );
230                    if ( entityRef != null ) {
231                            return entityRef.get();
232                    }
233                    return null;
234            }
235    
236            protected KimPrincipalInfo getPrincipalByIdCache( String principalId ) {
237                    MaxAgeSoftReference<KimPrincipalInfo> principalRef = principalByIdCache.get( principalId );
238                    if ( principalRef != null ) {
239                            return principalRef.get();
240                    }
241                    return null;
242            }
243    
244            protected KimPrincipalInfo getPrincipalByNameCache( String principalName ) {
245                    MaxAgeSoftReference<KimPrincipalInfo> principalRef = principalByNameCache.get( principalName );
246                    if ( principalRef != null ) {
247                            return principalRef.get();
248                    }
249                    return null;
250            }
251    
252            protected GroupInfo getGroupByIdCache( String groupId ) {
253                    MaxAgeSoftReference<GroupInfo> groupRef = groupByIdCache.get( groupId );
254                    if ( groupRef != null ) {
255                            return groupRef.get();
256                    }
257                    return null;
258            }
259    
260            protected GroupInfo getGroupByNameCache( String groupName ) {
261                    MaxAgeSoftReference<GroupInfo> groupRef = groupByNameCache.get( groupName );
262                    if ( groupRef != null ) {
263                            return groupRef.get();
264                    }
265                    return null;
266            }
267    
268            protected List<String> getGroupIdsForPrincipalCache( String principalId ) {
269                    MaxAgeSoftReference<List<String>> groupIdsRef = groupIdsForPrincipalCache.get( principalId );
270                    if ( groupIdsRef != null ) {
271                            return groupIdsRef.get();
272                    }
273                    return null;
274            }
275    
276            protected List<? extends GroupInfo> getGroupsForPrincipalCache( String principalId ) {
277                    MaxAgeSoftReference<List<? extends GroupInfo>> groupsRef = groupsForPrincipalCache.get( principalId );
278                    if ( groupsRef != null ) {
279                            return groupsRef.get();
280                    }
281                    return null;
282            }
283    
284            protected Boolean getIsMemberOfGroupCache( String principalId, String groupId ) {
285                    MaxAgeSoftReference<Boolean> isMemberRef = isMemberOfGroupCache.get( principalId + "-" + groupId );
286                    if ( isMemberRef != null ) {
287                            return isMemberRef.get();
288                    }
289                    return null;
290            }
291    
292            protected Boolean getIsGroupMemberOfGroupCache( String potentialMemberId, String potentialParentId )
293            {
294                    MaxAgeSoftReference<Boolean> isMemberRef = isGroupMemberOfGroupCache.get( potentialMemberId + "-" + potentialParentId );
295                    if ( isMemberRef != null ) {
296                            return isMemberRef.get();
297                    }
298                    return null;
299            }
300    
301            protected List<String> getGroupMemberPrincipalIdsCache( String groupId ) {
302                    MaxAgeSoftReference<List<String>> memberIdsRef = groupMemberPrincipalIdsCache.get( groupId );
303                    if ( memberIdsRef != null ) {
304                            return memberIdsRef.get();
305                    }
306                    return null;
307            }
308    
309            protected Boolean getHasPermissionCache( String key ) {
310                    MaxAgeSoftReference<Boolean> hasPermissionRef = hasPermissionCache.get( key );
311                    if ( hasPermissionRef != null ) {
312                            return hasPermissionRef.get();
313                    }
314                    return null;
315            }
316    
317            protected Boolean getHasPermissionByTemplateCache( String key ) {
318                    MaxAgeSoftReference<Boolean> hasPermissionRef = hasPermissionByTemplateCache.get( key );
319                    if ( hasPermissionRef != null ) {
320                            return hasPermissionRef.get();
321                    }
322                    return null;
323            }
324    
325            protected Boolean getIsAuthorizedByTemplateNameFromCache( String key ) {
326                    MaxAgeSoftReference<Boolean> cacheEntryRef = isAuthorizedByTemplateNameCache.get( key );
327                    if ( cacheEntryRef != null ) {
328                            return cacheEntryRef.get();
329                    }
330                    return null;
331            }
332    
333            protected Boolean getIsAuthorizedFromCache( String key ) {
334                    MaxAgeSoftReference<Boolean> cacheEntryRef = isAuthorizedCache.get( key );
335                    if ( cacheEntryRef != null ) {
336                            return cacheEntryRef.get();
337                    }
338                    return null;
339            }
340    
341            protected void addEntityToCache( KimEntity entity ) {
342                    if ( entity != null ) {
343                            entityCache.put( "entityId="+entity.getEntityId(), new MaxAgeSoftReference<KimEntity>( entityPrincipalCacheMaxAgeSeconds, entity ) );
344                            for ( KimPrincipal p : entity.getPrincipals() ) {
345                                    entityCache.put( "principalId="+p.getPrincipalId(), new MaxAgeSoftReference<KimEntity>( entityPrincipalCacheMaxAgeSeconds, entity ) );
346                                    entityCache.put( "principalName="+p.getPrincipalName(), new MaxAgeSoftReference<KimEntity>( entityPrincipalCacheMaxAgeSeconds, entity ) );
347                            }
348                    }
349            }
350    
351            protected void addEntityDefaultInfoToCache( KimEntityDefaultInfo entity ) {
352                    if ( entity != null ) {
353                            entityDefaultInfoCache.put( "entityId="+entity.getEntityId(), new MaxAgeSoftReference<KimEntityDefaultInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
354                            for ( KimPrincipal p : entity.getPrincipals() ) {
355                                    entityDefaultInfoCache.put( "principalId="+p.getPrincipalId(), new MaxAgeSoftReference<KimEntityDefaultInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
356                                    entityDefaultInfoCache.put( "principalName="+p.getPrincipalName(), new MaxAgeSoftReference<KimEntityDefaultInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
357                            }
358                    }
359            }
360    
361            protected void addEntityInfoToCache( KimEntityInfo entity ) {
362                    if ( entity != null ) {
363                            entityInfoCache.put( "entityId="+entity.getEntityId(), new MaxAgeSoftReference<KimEntityInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
364                            for ( KimPrincipal p : entity.getPrincipals() ) {
365                                    entityInfoCache.put( "principalId="+p.getPrincipalId(), new MaxAgeSoftReference<KimEntityInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
366                                    entityInfoCache.put( "principalName="+p.getPrincipalName(), new MaxAgeSoftReference<KimEntityInfo>( entityPrincipalCacheMaxAgeSeconds, entity ) );
367                            }
368                    }
369            }
370    
371            protected void addPrincipalToCache( KimPrincipalInfo principal ) {
372                    if ( principal != null ) {
373                            principalByNameCache.put( principal.getPrincipalName(), new MaxAgeSoftReference<KimPrincipalInfo>( entityPrincipalCacheMaxAgeSeconds, principal ) );
374                            principalByIdCache.put( principal.getPrincipalId(), new MaxAgeSoftReference<KimPrincipalInfo>( entityPrincipalCacheMaxAgeSeconds, principal ) );
375                    }
376            }
377    
378            protected void addGroupToCache( GroupInfo group ) {
379                    if ( group != null ) {
380                            groupByNameCache.put( group.getGroupName(), new MaxAgeSoftReference<GroupInfo>( groupCacheMaxAgeSeconds, group ) );
381                            groupByIdCache.put( group.getGroupId(), new MaxAgeSoftReference<GroupInfo>( groupCacheMaxAgeSeconds, group ) );
382                    }
383            }
384    
385            protected void addGroupIdsForPrincipalToCache( String principalId, List<String> ids ) {
386                    if ( ids != null ) {
387                            groupIdsForPrincipalCache.put( principalId, new MaxAgeSoftReference<List<String>>( groupCacheMaxAgeSeconds, ids ) );
388                    }
389            }
390    
391            protected void addGroupsForPrincipalToCache( String principalId, List<? extends GroupInfo> groups ) {
392                    if ( groups != null ) {
393                            groupsForPrincipalCache.put( principalId, new MaxAgeSoftReference<List<? extends GroupInfo>>( groupCacheMaxAgeSeconds, groups ) );
394                            List<String> groupIds = new ArrayList<String>( groups.size() );
395                            for ( GroupInfo group : groups ) {
396                                    groupIds.add( group.getGroupId() );
397                            }
398                            addGroupIdsForPrincipalToCache( principalId, groupIds );
399                    }
400            }
401    
402            protected void addIsMemberOfGroupToCache( String principalId, String groupId, boolean member ) {
403                    isMemberOfGroupCache.put( principalId + "-" + groupId, new MaxAgeSoftReference<Boolean>( groupCacheMaxAgeSeconds, member ) );
404            }
405    
406            protected void addIsGroupMemberOfGroupToCache( String potentialMemberId, String potentialParentId, boolean member )
407            {
408            isMemberOfGroupCache.put( potentialMemberId + "-" + potentialParentId, new MaxAgeSoftReference<Boolean>( groupCacheMaxAgeSeconds, member ) );
409        }
410    
411            protected void addGroupMemberPrincipalIdsToCache( String groupId, List<String> ids ) {
412                    if ( ids != null ) {
413                            groupMemberPrincipalIdsCache.put( groupId, new MaxAgeSoftReference<List<String>>( groupCacheMaxAgeSeconds, ids ) );
414                    }
415            }
416    
417            protected void addHasPermissionToCache( String key, boolean hasPerm ) {
418                    hasPermissionCache.put( key, new MaxAgeSoftReference<Boolean>( permissionCacheMaxAgeSeconds, hasPerm ) );
419            }
420    
421            protected void addHasPermissionByTemplateToCache( String key, boolean hasPerm ) {
422                    hasPermissionByTemplateCache.put( key, new MaxAgeSoftReference<Boolean>( permissionCacheMaxAgeSeconds, hasPerm ) );
423            }
424    
425            protected void addIsAuthorizedByTemplateNameToCache( String key, boolean authorized ) {
426                    isAuthorizedByTemplateNameCache.put( key, new MaxAgeSoftReference<Boolean>( permissionCacheMaxAgeSeconds, authorized ) );
427            }
428    
429            protected void addIsAuthorizedToCache( String key, boolean authorized ) {
430                    isAuthorizedCache.put( key, new MaxAgeSoftReference<Boolean>( permissionCacheMaxAgeSeconds, authorized ) );
431            }
432    
433            // AUTHENTICATION SERVICE
434    
435            public String getAuthenticatedPrincipalName(HttpServletRequest request) {
436                    return getAuthenticationService().getPrincipalName(request);
437            }
438    
439        // AUTHORIZATION SERVICE
440        @Transactional(readOnly=true)
441        public boolean hasPermission(String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails) {
442            if ( LOG.isDebugEnabled() ) {
443                    logHasPermissionCheck("Permission", principalId, namespaceCode, permissionName, permissionDetails);
444            }
445            StringBuffer cacheKey = new StringBuffer();
446            cacheKey.append( principalId ).append(  '/' );
447            cacheKey.append( namespaceCode ).append( '-' ).append( permissionName ).append( '/' );
448            addAttributeSetToKey( permissionDetails, cacheKey );
449            String key = cacheKey.toString();
450            Boolean hasPerm = getHasPermissionCache(key);
451                    if (hasPerm == null) {
452                            hasPerm = getPermissionService().hasPermission( principalId, namespaceCode, permissionName, permissionDetails );
453                    addHasPermissionToCache(key, hasPerm);
454                    if ( LOG.isDebugEnabled() ) {
455                            LOG.debug( "Result: " + hasPerm );
456                    }
457                    } else {
458                            if ( LOG.isDebugEnabled() ) {
459                                    LOG.debug( "Result Found in cache using key: " + key + "\nResult: " + hasPerm );
460                            }
461                    }
462            return hasPerm;
463        }
464    
465        @Transactional(readOnly=true)
466        public boolean isAuthorized(String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification ) {
467            if ( qualification == null || qualification.isEmpty() ) {
468                    return hasPermission( principalId, namespaceCode, permissionName, permissionDetails );
469            }
470            if ( LOG.isDebugEnabled() ) {
471                    logAuthorizationCheck("Permission", principalId, namespaceCode, permissionName, permissionDetails, qualification);
472            }
473            StringBuffer cacheKey = new StringBuffer();
474            cacheKey.append( principalId ).append(  '/' );
475            cacheKey.append( namespaceCode ).append( '-' ).append( permissionName ).append( '/' );
476            addAttributeSetToKey( permissionDetails, cacheKey );
477            cacheKey.append( '/' );
478            addAttributeSetToKey( qualification, cacheKey );
479            String key = cacheKey.toString();
480            Boolean isAuthorized = getIsAuthorizedFromCache( key );
481            if ( isAuthorized == null ) {
482                    isAuthorized = getPermissionService().isAuthorized( principalId, namespaceCode, permissionName, permissionDetails, qualification );
483                    addIsAuthorizedToCache( key, isAuthorized );
484                    if ( LOG.isDebugEnabled() ) {
485                            LOG.debug( "Result: " + isAuthorized );
486                    }
487                    } else {
488                            if ( LOG.isDebugEnabled() ) {
489                                    LOG.debug( "Result Found in cache using key: " + key + "\nResult: " + isAuthorized );
490                            }
491            }
492            return isAuthorized;
493        }
494    
495        @Transactional(readOnly=true)
496        public boolean hasPermissionByTemplateName(String principalId, String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails) {
497            if ( LOG.isDebugEnabled() ) {
498                    logHasPermissionCheck("Perm Templ", principalId, namespaceCode, permissionTemplateName, permissionDetails);
499            }
500            StringBuffer cacheKey = new StringBuffer();
501            cacheKey.append( principalId ).append(  '/' );
502            cacheKey.append( namespaceCode ).append( '-' ).append( permissionTemplateName ).append( '/' );
503            addAttributeSetToKey( permissionDetails, cacheKey );
504            String key = cacheKey.toString();
505            Boolean hasPerm = getHasPermissionByTemplateCache(key);
506                    if (hasPerm == null) {
507                            hasPerm = getPermissionService().hasPermissionByTemplateName( principalId, namespaceCode, permissionTemplateName, permissionDetails );
508                    addHasPermissionByTemplateToCache(key, hasPerm);
509                    if ( LOG.isDebugEnabled() ) {
510                            LOG.debug( "Result: " + hasPerm );
511                    }
512                    } else {
513                            if ( LOG.isDebugEnabled() ) {
514                                    LOG.debug( "Result Found in cache using key: " + key + "\nResult: " + hasPerm );
515                            }
516                    }
517            return hasPerm;
518        }
519        
520        @Transactional(readOnly=true)
521        public boolean isAuthorizedByTemplateName(String principalId, String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails, AttributeSet qualification ) {
522            if ( qualification == null || qualification.isEmpty() ) {
523                    return hasPermissionByTemplateName( principalId, namespaceCode, permissionTemplateName, permissionDetails );
524            }
525            if ( LOG.isDebugEnabled() ) {
526                    logAuthorizationCheck("Perm Templ", principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification);
527            }
528            StringBuffer cacheKey = new StringBuffer();
529            cacheKey.append( principalId ).append(  '/' );
530            cacheKey.append( namespaceCode ).append( '-' ).append( permissionTemplateName ).append( '/' );
531            addAttributeSetToKey( permissionDetails, cacheKey );
532            cacheKey.append( '/' );
533            addAttributeSetToKey( qualification, cacheKey );
534            String key = cacheKey.toString();
535            Boolean isAuthorized = getIsAuthorizedByTemplateNameFromCache( key );
536            if ( isAuthorized == null ) {
537                    isAuthorized = getPermissionService().isAuthorizedByTemplateName( principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification );
538                    addIsAuthorizedByTemplateNameToCache( key, isAuthorized );
539                    if ( LOG.isDebugEnabled() ) {
540                            LOG.debug( "Result: " + isAuthorized );
541                    }
542                    } else {
543                            if ( LOG.isDebugEnabled() ) {
544                                    LOG.debug( "Result Found in cache using key: " + key + "\nResult: " + isAuthorized );
545                            }
546            }
547            return isAuthorized;
548        }
549    
550            private void addAttributeSetToKey(AttributeSet attributes, StringBuffer key) {
551                    if ( attributes != null ) {
552                            for ( Map.Entry<String, String> entry : attributes.entrySet() ) {
553                                    key.append( entry.getKey() ).append( '=' ).append( entry.getValue() ).append('|');
554                    }
555                    } else {
556                            key.append( "[null]" );
557                    }
558            }
559    
560        /**
561         * @see org.kuali.rice.kim.service.IdentityManagementService#getAuthorizedPermissions(java.lang.String, String, java.lang.String, org.kuali.rice.kim.bo.types.dto.AttributeSet, org.kuali.rice.kim.bo.types.dto.AttributeSet)
562         */
563        public List<? extends KimPermissionInfo> getAuthorizedPermissions(String principalId,
564                    String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification) {
565            return getPermissionService().getAuthorizedPermissions( principalId, namespaceCode, permissionName, permissionDetails, qualification );
566        }
567        @Transactional(readOnly=true)
568        public List<? extends KimPermissionInfo> getAuthorizedPermissionsByTemplateName(String principalId,
569                    String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails, AttributeSet qualification) {
570            return getPermissionService().getAuthorizedPermissionsByTemplateName(principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification);
571        }
572        
573        @Transactional(readOnly=true)
574        public boolean isPermissionDefinedForTemplateName(String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails) {
575            StringBuffer key = new StringBuffer();
576            key.append( namespaceCode ).append( '-' ).append( permissionTemplateName ).append( '/' );
577            addAttributeSetToKey(permissionDetails, key);
578            MaxAgeSoftReference<Boolean> resultEntry = isPermissionDefinedForTemplateNameCache.get(key.toString());
579            if ( resultEntry != null ) {
580                Boolean result = resultEntry.get();
581                if ( result != null ) {
582                    return result;
583                }
584            }
585            boolean result = getPermissionService().isPermissionDefinedForTemplateName(namespaceCode, permissionTemplateName, permissionDetails);
586            isPermissionDefinedForTemplateNameCache.put(key.toString(),new MaxAgeSoftReference<Boolean>( permissionCacheMaxAgeSeconds, result ));
587            return result;
588        }
589    
590    
591            public List<PermissionAssigneeInfo> getPermissionAssignees(String namespaceCode,
592                            String permissionName, AttributeSet permissionDetails, AttributeSet qualification) {
593                    return this.permissionService.getPermissionAssignees( namespaceCode, permissionName,
594                                    permissionDetails, qualification );
595            }
596    
597            public List<PermissionAssigneeInfo> getPermissionAssigneesForTemplateName(String namespaceCode,
598                            String permissionTemplateName, AttributeSet permissionDetails,
599                            AttributeSet qualification) {
600                    return this.permissionService.getPermissionAssigneesForTemplateName( namespaceCode,
601                                    permissionTemplateName, permissionDetails, qualification );
602            }
603    
604        // GROUP SERVICE
605    
606            public boolean isMemberOfGroup(String principalId, String groupId) {
607            Boolean isMember = getIsMemberOfGroupCache(principalId, groupId);
608                    if (isMember != null) {
609                            return isMember;
610                    }
611                    isMember = getGroupService().isMemberOfGroup(principalId, groupId);
612            addIsMemberOfGroupToCache(principalId, groupId, isMember);
613            return isMember;
614            }
615    
616            public boolean isMemberOfGroup(String principalId, String namespaceCode, String groupName) {
617                    GroupInfo group = getGroupByName(namespaceCode, groupName);
618                    if ( group == null ) {
619                            return false;
620                    }
621                    return isMemberOfGroup(principalId, group.getGroupId());
622        }
623    
624            public boolean isGroupMemberOfGroup(String potentialMemberId, String potentialParentId)
625            {
626                Boolean isMember = getIsGroupMemberOfGroupCache(potentialMemberId, potentialParentId);
627                if(isMember != null)
628                {
629                    return isMember;
630                }
631                else
632            {
633                    isMember = getGroupService()
634                            .isGroupMemberOfGroup(potentialMemberId, potentialParentId);
635            }
636                addIsGroupMemberOfGroupToCache(potentialMemberId, potentialParentId, isMember);
637                return isMember;
638            }
639            public List<String> getGroupMemberPrincipalIds(String groupId) {
640            List<String> ids = getGroupMemberPrincipalIdsCache(groupId);
641                    if (ids != null) {
642                            return ids;
643                    }
644                    ids = getGroupService().getMemberPrincipalIds(groupId);
645            addGroupMemberPrincipalIdsToCache(groupId, ids);
646            return ids;
647            }
648    
649            public List<String> getDirectGroupMemberPrincipalIds(String groupId) {
650                    return getGroupService().getDirectMemberPrincipalIds(groupId);
651            }
652    
653        public List<String> getGroupIdsForPrincipal(String principalId) {
654            List<String> ids = getGroupIdsForPrincipalCache(principalId);
655                    if (ids != null) {
656                            return ids;
657                    }
658                    ids = getGroupService().getGroupIdsForPrincipal(principalId);
659            addGroupIdsForPrincipalToCache(principalId, ids);
660            return ids;
661            }
662    
663        public List<String> getGroupIdsForPrincipal(String principalId, String namespaceCode ) {
664                    return getGroupService().getGroupIdsForPrincipalByNamespace(principalId, namespaceCode );
665            }
666    
667        public List<? extends GroupInfo> getGroupsForPrincipal(String principalId) {
668            List<? extends GroupInfo> groups = getGroupsForPrincipalCache(principalId);
669                    if (groups != null) {
670                            return groups;
671                    }
672                    groups = getGroupService().getGroupsForPrincipal(principalId);
673            addGroupsForPrincipalToCache(principalId, groups);
674            return groups;
675            }
676    
677        public List<? extends GroupInfo> getGroupsForPrincipal(String principalId, String namespaceCode ) {
678            List<? extends GroupInfo> groups = getGroupsForPrincipalCache(principalId + "-" + namespaceCode);
679                    if (groups != null) {
680                            return groups;
681                    }
682                    groups = getGroupService().getGroupsForPrincipalByNamespace(principalId, namespaceCode );
683            addGroupsForPrincipalToCache(principalId, groups);
684            return groups;
685            }
686    
687        public List<String> getMemberGroupIds(String groupId) {
688                    return getGroupService().getMemberGroupIds(groupId);
689            }
690    
691        public List<String> getDirectMemberGroupIds(String groupId) {
692                    return getGroupService().getDirectMemberGroupIds(groupId);
693            }
694    
695        public GroupInfo getGroup(String groupId) {
696            GroupInfo group = getGroupByIdCache(groupId);
697                    if (group != null) {
698                            return group;
699                    }
700                    group = getGroupService().getGroupInfo(groupId);
701            addGroupToCache(group);
702            return group;
703            }
704    
705        public GroupInfo getGroupByName(String namespaceCode, String groupName) {
706            GroupInfo group = getGroupByNameCache(namespaceCode + "-" + groupName);
707                    if (group != null) {
708                            return group;
709                    }
710                    group = getGroupService().getGroupInfoByName( namespaceCode, groupName );
711            addGroupToCache(group);
712            return group;
713        }
714    
715        public List<String> getParentGroupIds(String groupId) {
716                    return getGroupService().getParentGroupIds( groupId );
717            }
718    
719        public List<String> getDirectParentGroupIds(String groupId) {
720                    return getGroupService().getDirectParentGroupIds( groupId );
721            }
722    
723        protected void clearGroupCachesForPrincipalAndGroup( String principalId, String groupId ) {
724            if ( principalId != null ) {
725                    groupIdsForPrincipalCache.remove(principalId);
726                    groupsForPrincipalCache.remove(principalId);
727                    isMemberOfGroupCache.remove(principalId + "-" + groupId);
728            } else {
729                    // added or removed a group - perform a more extensive purge
730                    synchronized (isMemberOfGroupCache) {
731                    Iterator<String> keys = isMemberOfGroupCache.keySet().iterator();
732                    while ( keys.hasNext() ) {
733                            String key = keys.next();
734                            if ( key.endsWith("-"+groupId) ) {
735                                    keys.remove();
736                            }
737                    }
738                            }
739                    // NOTE: There's no good way to selectively purge the other two group caches or the permission caches which could be
740                    // affected - is this necessary or do we just wait for the cache items to expire
741            }
742            groupMemberPrincipalIdsCache.remove(groupId);
743        }
744    
745    
746        public boolean addGroupToGroup(String childId, String parentId) {
747            clearGroupCachesForPrincipalAndGroup(null, parentId);
748            return getGroupUpdateService().addGroupToGroup(childId, parentId);
749        }
750    
751        public boolean addPrincipalToGroup(String principalId, String groupId) {
752            clearGroupCachesForPrincipalAndGroup(principalId, groupId);
753            return getGroupUpdateService().addPrincipalToGroup(principalId, groupId);
754        }
755    
756        public boolean removeGroupFromGroup(String childId, String parentId) {
757            clearGroupCachesForPrincipalAndGroup(null, parentId);
758            return getGroupUpdateService().removeGroupFromGroup(childId, parentId);
759        }
760    
761        public boolean removePrincipalFromGroup(String principalId, String groupId) {
762            clearGroupCachesForPrincipalAndGroup(principalId, groupId);
763            return getGroupUpdateService().removePrincipalFromGroup(principalId, groupId);
764        }
765    
766        /**
767             * This delegate method ...
768             *
769             * @param groupInfo
770             * @return
771             * @see org.kuali.rice.kim.service.GroupUpdateService#createGroup(org.kuali.rice.kim.bo.group.dto.GroupInfo)
772             */
773            public GroupInfo createGroup(GroupInfo groupInfo) {
774            clearGroupCachesForPrincipalAndGroup(null,groupInfo.getGroupId());
775                    return getGroupUpdateService().createGroup(groupInfo);
776            }
777    
778            /**
779             * This delegate method ...
780             *
781             * @param groupId
782             * @see org.kuali.rice.kim.service.GroupUpdateService#removeAllGroupMembers(java.lang.String)
783             */
784            public void removeAllGroupMembers(String groupId) {
785            clearGroupCachesForPrincipalAndGroup(null, groupId);
786                    getGroupUpdateService().removeAllGroupMembers(groupId);
787            }
788    
789            /**
790             * This delegate method ...
791             *
792             * @param groupId
793             * @param groupInfo
794             * @return
795             * @see org.kuali.rice.kim.service.GroupUpdateService#updateGroup(java.lang.String, org.kuali.rice.kim.bo.group.dto.GroupInfo)
796             */
797            public GroupInfo updateGroup(String groupId, GroupInfo groupInfo) {
798            clearGroupCachesForPrincipalAndGroup(null, groupId);
799                    return getGroupUpdateService().updateGroup(groupId, groupInfo);
800            }
801    
802    
803        // IDENTITY SERVICE
804    
805            public KimPrincipalInfo getPrincipal(String principalId) {
806            KimPrincipalInfo principal = getPrincipalByIdCache(principalId);
807                    if (principal != null) {
808                            return principal;
809                    }
810                    principal = getIdentityService().getPrincipal(principalId);
811            addPrincipalToCache(principal);
812            return principal;
813            }
814            @Transactional(readOnly=true)
815        public KimPrincipalInfo getPrincipalByPrincipalName(String principalName) {
816            KimPrincipalInfo principal = getPrincipalByNameCache(principalName);
817                    if (principal != null) {
818                            return principal;
819                    }
820                    principal = getIdentityService().getPrincipalByPrincipalName(principalName);
821            addPrincipalToCache(principal);
822            return principal;
823        }
824    
825        /**
826         * @see org.kuali.rice.kim.service.IdentityManagementService#getPrincipalByPrincipalNameAndPassword(java.lang.String, java.lang.String)
827         */
828        public KimPrincipalInfo getPrincipalByPrincipalNameAndPassword(String principalName, String password) {
829            // TODO: cache this?
830            return getIdentityService().getPrincipalByPrincipalNameAndPassword( principalName, password );
831        }
832    
833        /**
834         * This overridden method ...
835         *
836         * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityDefaultInfo(java.lang.String)
837         */
838        public KimEntityDefaultInfo getEntityDefaultInfo(String entityId) {
839            KimEntityDefaultInfo entity = getEntityDefaultInfoFromCache( entityId );
840            if ( entity == null ) {
841                    entity = getIdentityService().getEntityDefaultInfo(entityId);
842                    addEntityDefaultInfoToCache( entity );
843            }
844            return entity;
845        }
846    
847        /**
848         * This overridden method ...
849         *
850         * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityDefaultInfoByPrincipalId(java.lang.String)
851         */
852        @Transactional(readOnly=true)
853        public KimEntityDefaultInfo getEntityDefaultInfoByPrincipalId(
854                    String principalId) {
855            KimEntityDefaultInfo entity = getEntityDefaultInfoFromCacheByPrincipalId( principalId );
856            if ( entity == null ) {
857                    entity = getIdentityService().getEntityDefaultInfoByPrincipalId(principalId);
858                            addEntityDefaultInfoToCache( entity );
859            }
860            return entity;
861        }
862    
863        /**
864         * This overridden method ...
865         *
866         * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityDefaultInfoByPrincipalName(java.lang.String)
867         */
868        public KimEntityDefaultInfo getEntityDefaultInfoByPrincipalName(
869                    String principalName) {
870            KimEntityDefaultInfo entity = getEntityDefaultInfoFromCacheByPrincipalName( principalName );
871            if ( entity == null ) {
872                    entity = getIdentityService().getEntityDefaultInfoByPrincipalName(principalName);
873                            addEntityDefaultInfoToCache( entity );
874            }
875            return entity;
876        }
877    
878        /**
879         * This overridden method ...
880         *
881         * @see org.kuali.rice.kim.service.IdentityManagementService#lookupEntityDefaultInfo(Map, boolean)
882         */
883        @Transactional(readOnly=true)
884        public List<? extends KimEntityDefaultInfo> lookupEntityDefaultInfo(
885                    Map<String, String> searchCriteria, boolean unbounded) {
886            return getIdentityService().lookupEntityDefaultInfo(searchCriteria, unbounded);
887        }
888    
889    
890        /**
891             * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityInfo(java.lang.String)
892             */
893            public KimEntityInfo getEntityInfo(String entityId) {
894            KimEntityInfo entity = getEntityInfoFromCache( entityId );
895            if ( entity == null ) {
896                    entity = getIdentityService().getEntityInfo(entityId);
897                    addEntityInfoToCache( entity );
898            }
899            return entity;
900            }
901    
902            /**
903             * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityInfoByPrincipalId(java.lang.String)
904             */
905            @Transactional(readOnly=true)
906            public KimEntityInfo getEntityInfoByPrincipalId(String principalId) {
907            KimEntityInfo entity = getEntityInfoFromCacheByPrincipalId( principalId );
908            if ( entity == null ) {
909                    entity = getIdentityService().getEntityInfoByPrincipalId(principalId);
910                            addEntityInfoToCache( entity );
911            }
912            return entity;
913            }
914    
915            /**
916             * This overridden method ...
917             *
918             * @see org.kuali.rice.kim.service.IdentityManagementService#getEntityInfoByPrincipalName(java.lang.String)
919             */
920            public KimEntityInfo getEntityInfoByPrincipalName(String principalName) {
921                    KimEntityInfo entity = getEntityInfoFromCacheByPrincipalName( principalName );
922            if ( entity == null ) {
923                    entity = getIdentityService().getEntityInfoByPrincipalName( principalName );
924                            addEntityInfoToCache( entity );
925            }
926            return entity;
927            }
928    
929            /**
930             * @see org.kuali.rice.kim.service.IdentityManagementService#lookupEntityInfo(java.util.Map, boolean)
931             */
932        @Transactional(readOnly=true)
933            public List<KimEntityInfo> lookupEntityInfo(
934                            Map<String, String> searchCriteria, boolean unbounded) {
935                    return getIdentityService().lookupEntityInfo(searchCriteria, unbounded);
936            }
937    
938            /**
939         * @see org.kuali.rice.kim.service.IdentityManagementService#getMatchingEntityCount(java.util.Map)
940         */
941        public int getMatchingEntityCount(Map<String,String> searchCriteria) {
942            return getIdentityService().getMatchingEntityCount( searchCriteria );
943        }
944    
945            public AddressTypeInfo getAddressType( String code ) {
946                    AddressTypeInfo type = (AddressTypeInfo)kimReferenceTypeCache.get(AddressTypeInfo.class.getSimpleName()+"-"+code);
947                    if ( type == null ) {
948                            type = getIdentityService().getAddressType(code);
949                            kimReferenceTypeCache.put(AddressTypeInfo.class.getSimpleName()+"-"+code, type);
950                    }
951                    return type;
952            }
953            public AffiliationTypeInfo getAffiliationType( String code ) {
954                    AffiliationTypeInfo type = (AffiliationTypeInfo)kimReferenceTypeCache.get(AffiliationTypeInfo.class.getSimpleName()+"-"+code);
955                    if ( type == null ) {
956                            type = getIdentityService().getAffiliationType(code);
957                            kimReferenceTypeCache.put(AddressTypeInfo.class.getSimpleName()+"-"+code, type);
958                    }
959                    return type;
960            }
961            public CitizenshipStatusInfo getCitizenshipStatus( String code ) {
962                    CitizenshipStatusInfo type = (CitizenshipStatusInfo)kimReferenceTypeCache.get(CitizenshipStatusInfo.class.getSimpleName()+"-"+code);
963                    if ( type == null ) {
964                            type = getIdentityService().getCitizenshipStatus(code);
965                            kimReferenceTypeCache.put(CitizenshipStatusInfo.class.getSimpleName()+"-"+code, type);
966                    }
967                    return type;
968            }
969            public EmailTypeInfo getEmailType( String code ) {
970                    EmailTypeInfo type = (EmailTypeInfo)kimReferenceTypeCache.get(EmailTypeInfo.class.getSimpleName()+"-"+code);
971                    if ( type == null ) {
972                            type = getIdentityService().getEmailType(code);
973                            kimReferenceTypeCache.put(EmailTypeInfo.class.getSimpleName()+"-"+code, type);
974                    }
975                    return type;
976            }
977            public EmploymentStatusInfo getEmploymentStatus( String code ) {
978                    EmploymentStatusInfo type = (EmploymentStatusInfo)kimReferenceTypeCache.get(EmploymentStatusInfo.class.getSimpleName()+"-"+code);
979                    if ( type == null ) {
980                            type = getIdentityService().getEmploymentStatus(code);
981                            kimReferenceTypeCache.put(EmploymentStatusInfo.class.getSimpleName()+"-"+code, type);
982                    }
983                    return type;
984            }
985            public EmploymentTypeInfo getEmploymentType( String code ) {
986                    EmploymentTypeInfo type = (EmploymentTypeInfo)kimReferenceTypeCache.get(EmploymentTypeInfo.class.getSimpleName()+"-"+code);
987                    if ( type == null ) {
988                            type = getIdentityService().getEmploymentType(code);
989                            kimReferenceTypeCache.put(EmploymentTypeInfo.class.getSimpleName()+"-"+code, type);
990                    }
991                    return type;
992            }
993            public EntityNameTypeInfo getEntityNameType( String code ) {
994                    EntityNameTypeInfo type = (EntityNameTypeInfo)kimReferenceTypeCache.get(EntityNameTypeInfo.class.getSimpleName()+"-"+code);
995                    if ( type == null ) {
996                            type = getIdentityService().getEntityNameType(code);
997                            kimReferenceTypeCache.put(EntityNameTypeInfo.class.getSimpleName()+"-"+code, type);
998                    }
999                    return type;
1000            }
1001            public EntityTypeInfo getEntityType( String code ) {
1002                    EntityTypeInfo type = (EntityTypeInfo)kimReferenceTypeCache.get(EntityTypeInfo.class.getSimpleName()+"-"+code);
1003                    if ( type == null ) {
1004                            type = getIdentityService().getEntityType(code);
1005                            kimReferenceTypeCache.put(EntityTypeInfo.class.getSimpleName()+"-"+code, type);
1006                    }
1007                    return type;
1008            }
1009            public ExternalIdentifierTypeInfo getExternalIdentifierType( String code ) {
1010                    ExternalIdentifierTypeInfo type = (ExternalIdentifierTypeInfo)kimReferenceTypeCache.get(ExternalIdentifierTypeInfo.class.getSimpleName()+"-"+code);
1011                    if ( type == null ) {
1012                            type = getIdentityService().getExternalIdentifierType(code);
1013                            kimReferenceTypeCache.put(ExternalIdentifierTypeInfo.class.getSimpleName()+"-"+code, type);
1014                    }
1015                    return type;
1016            }
1017            public PhoneTypeInfo getPhoneType( String code ) {
1018                    PhoneTypeInfo type = (PhoneTypeInfo)kimReferenceTypeCache.get(PhoneTypeInfo.class.getSimpleName()+"-"+code);
1019                    if ( type == null ) {
1020                            type = getIdentityService().getPhoneType(code);
1021                            kimReferenceTypeCache.put(PhoneTypeInfo.class.getSimpleName()+"-"+code, type);
1022                    }
1023                    return type;
1024            }
1025    
1026            // OTHER METHODS
1027    
1028    
1029    
1030            public AuthenticationService getAuthenticationService() {
1031                    if ( authenticationService == null ) {
1032                            authenticationService = KIMServiceLocator.getAuthenticationService();
1033                    }
1034                    return authenticationService;
1035            }
1036    
1037            public IdentityService getIdentityService() {
1038                    if ( identityService == null ) {
1039                            identityService = KIMServiceLocator.getIdentityService();
1040                    }
1041                    return identityService;
1042            }
1043    
1044            public GroupService getGroupService() {
1045                    if ( groupService == null ) {
1046                            groupService = KIMServiceLocator.getGroupService();
1047                    }
1048                    return groupService;
1049            }
1050    
1051            public PermissionService getPermissionService() {
1052                    if ( permissionService == null ) {
1053                            permissionService = KIMServiceLocator.getPermissionService();
1054                    }
1055                    return permissionService;
1056            }
1057    
1058            public ResponsibilityService getResponsibilityService() {
1059                    if ( responsibilityService == null ) {
1060                            responsibilityService = KIMServiceLocator.getResponsibilityService();
1061                    }
1062                    return responsibilityService;
1063            }
1064    
1065        // ----------------------
1066        // Responsibility Methods
1067        // ----------------------
1068    
1069            /**
1070             * @see org.kuali.rice.kim.service.IdentityManagementService#getResponsibility(java.lang.String)
1071             */
1072            public KimResponsibilityInfo getResponsibility(String responsibilityId) {
1073                    return getResponsibilityService().getResponsibility( responsibilityId );
1074            }
1075    
1076            /**
1077             * @see org.kuali.rice.kim.service.IdentityManagementService#hasResponsibility(java.lang.String, String, java.lang.String, AttributeSet, AttributeSet)
1078             */
1079        @Transactional(readOnly=true)
1080            public boolean hasResponsibility(String principalId, String namespaceCode,
1081                            String responsibilityName, AttributeSet qualification,
1082                            AttributeSet responsibilityDetails) {
1083                    return getResponsibilityService().hasResponsibility( principalId, namespaceCode, responsibilityName, qualification, responsibilityDetails );
1084            }
1085    
1086            public List<? extends KimResponsibilityInfo> getResponsibilitiesByName( String namespaceCode, String responsibilityName) {
1087                    return getResponsibilityService().getResponsibilitiesByName( namespaceCode, responsibilityName );
1088            }
1089    
1090            public List<ResponsibilityActionInfo> getResponsibilityActions( String namespaceCode, String responsibilityName,
1091                    AttributeSet qualification, AttributeSet responsibilityDetails) {
1092                    return getResponsibilityService().getResponsibilityActions( namespaceCode, responsibilityName, qualification, responsibilityDetails );
1093            }
1094    
1095            /**
1096             * This overridden method ...
1097             *
1098             * @see org.kuali.rice.kim.service.IdentityManagementService#getResponsibilityActionsByTemplateName(java.lang.String, java.lang.String, org.kuali.rice.kim.bo.types.dto.AttributeSet, org.kuali.rice.kim.bo.types.dto.AttributeSet)
1099             */
1100            public List<ResponsibilityActionInfo> getResponsibilityActionsByTemplateName(
1101                            String namespaceCode, String responsibilityTemplateName,
1102                            AttributeSet qualification, AttributeSet responsibilityDetails) {
1103                    return getResponsibilityService().getResponsibilityActionsByTemplateName(namespaceCode, responsibilityTemplateName, qualification, responsibilityDetails);
1104            }
1105    
1106            /**
1107             * This overridden method ...
1108             *
1109             * @see org.kuali.rice.kim.service.IdentityManagementService#hasResponsibilityByTemplateName(java.lang.String, java.lang.String, java.lang.String, org.kuali.rice.kim.bo.types.dto.AttributeSet, org.kuali.rice.kim.bo.types.dto.AttributeSet)
1110             */
1111        @Transactional(readOnly=true)
1112            public boolean hasResponsibilityByTemplateName(String principalId,
1113                            String namespaceCode, String responsibilityTemplateName,
1114                            AttributeSet qualification, AttributeSet responsibilityDetails) {
1115                    return getResponsibilityService().hasResponsibilityByTemplateName(principalId, namespaceCode, responsibilityTemplateName, qualification, responsibilityDetails);
1116            }
1117    
1118            public void setEntityPrincipalCacheMaxSize(int entityPrincipalCacheMaxSize) {
1119                    this.entityPrincipalCacheMaxSize = entityPrincipalCacheMaxSize;
1120            }
1121    
1122            public void setEntityPrincipalCacheMaxAgeSeconds(int entityPrincipalCacheMaxAge) {
1123                    this.entityPrincipalCacheMaxAgeSeconds = entityPrincipalCacheMaxAge;
1124            }
1125    
1126            public void setGroupCacheMaxSize(int groupCacheMaxSize) {
1127                    this.groupCacheMaxSize = groupCacheMaxSize;
1128            }
1129    
1130            public void setGroupCacheMaxAgeSeconds(int groupCacheMaxAge) {
1131                    this.groupCacheMaxAgeSeconds = groupCacheMaxAge;
1132            }
1133    
1134            public void setPermissionCacheMaxSize(int permissionCacheMaxSize) {
1135                    this.permissionCacheMaxSize = permissionCacheMaxSize;
1136            }
1137    
1138            public void setPermissionCacheMaxAgeSeconds(int permissionCacheMaxAge) {
1139                    this.permissionCacheMaxAgeSeconds = permissionCacheMaxAge;
1140            }
1141    
1142            public void setResponsibilityCacheMaxSize(int responsibilityCacheMaxSize) {
1143                    this.responsibilityCacheMaxSize = responsibilityCacheMaxSize;
1144            }
1145    
1146            public void setResponsibilityCacheMaxAgeSeconds(int responsibilityCacheMaxAge) {
1147                    this.responsibilityCacheMaxAgeSeconds = responsibilityCacheMaxAge;
1148            }
1149    
1150        protected void logAuthorizationCheck(String checkType, String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification ) {
1151                    StringBuilder sb = new StringBuilder();
1152                    sb.append(  '\n' );
1153                    sb.append( "Is AuthZ for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' );
1154                    sb.append( "             Principal:  " ).append( principalId );
1155                    if ( principalId != null ) {
1156                            KimPrincipalInfo principal = getPrincipal( principalId );
1157                            if ( principal != null ) {
1158                                    sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' );
1159                            }
1160                    }
1161                    sb.append( '\n' );
1162                    sb.append( "             Details:\n" );
1163                    if ( permissionDetails != null ) {
1164                            sb.append( permissionDetails.formattedDump( 25 ) );
1165                    } else {
1166                            sb.append( "                         [null]\n" );
1167                    }
1168                    sb.append( "             Qualifiers:\n" );
1169                    if ( qualification != null && !qualification.isEmpty() ) {
1170                            sb.append( qualification.formattedDump( 25 ) );
1171                    } else {
1172                            sb.append( "                         [null]\n" );
1173                    }
1174                    if (LOG.isTraceEnabled()) {
1175                            LOG.trace( sb.append( RiceDebugUtils.getTruncatedStackTrace(true)).toString() );
1176                    } else {
1177                            LOG.debug(sb.toString());
1178                    }
1179        }
1180    
1181        protected void logHasPermissionCheck(String checkType, String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails ) {
1182                    StringBuilder sb = new StringBuilder();
1183                    sb.append(  '\n' );
1184                    sb.append( "Has Perm for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' );
1185                    sb.append( "             Principal:  " ).append( principalId );
1186                    if ( principalId != null ) {
1187                            KimPrincipalInfo principal = getPrincipal( principalId );
1188                            if ( principal != null ) {
1189                                    sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' );
1190                            }
1191                    }
1192                    sb.append(  '\n' );
1193                    sb.append( "             Details:\n" );
1194                    if ( permissionDetails != null ) {
1195                            sb.append( permissionDetails.formattedDump( 25 ) );
1196                    } else {
1197                            sb.append( "                         [null]\n" );
1198                    }
1199                    if (LOG.isTraceEnabled()) {
1200                            LOG.trace( sb.append( RiceDebugUtils.getTruncatedStackTrace(true)).toString() );
1201                    } else {
1202                            LOG.debug(sb.toString());
1203                    }
1204        }
1205    
1206            public GroupUpdateService getGroupUpdateService() {
1207                    try {
1208                            if ( groupUpdateService == null ) {
1209                                    groupUpdateService = KIMServiceLocator.getGroupUpdateService();
1210                                    if ( groupUpdateService == null ) {
1211                                            throw new UnsupportedOperationException( "null returned for GroupUpdateService, unable to update group data");
1212                                    }
1213                            }
1214                    } catch ( Exception ex ) {
1215                            throw new UnsupportedOperationException( "unable to obtain a GroupUpdateService, unable to update group data", ex);
1216                    }
1217                    return groupUpdateService;
1218            }
1219    
1220            public IdentityUpdateService getIdentityUpdateService() {
1221                    try {
1222                            if ( identityUpdateService == null ) {
1223                                    identityUpdateService = KIMServiceLocator.getIdentityUpdateService();
1224                                    if ( identityUpdateService == null ) {
1225                                            throw new UnsupportedOperationException( "null returned for IdentityUpdateService, unable to update identity data");
1226                                    }
1227                            }
1228                    } catch ( Exception ex ) {
1229                            throw new UnsupportedOperationException( "unable to obtain an IdentityUpdateService, unable to update identity data", ex);
1230                    }
1231                    return identityUpdateService;
1232            }
1233    }