View Javadoc

1   /*
2    * Copyright 2007-2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kim.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.kuali.rice.core.api.config.property.ConfigContext;
21  import org.kuali.rice.core.util.AttributeSet;
22  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
23  import org.kuali.rice.kim.api.type.KimType;
24  import org.kuali.rice.kim.bo.Role;
25  import org.kuali.rice.kim.bo.impl.PermissionImpl;
26  import org.kuali.rice.kim.bo.role.dto.KimPermissionInfo;
27  import org.kuali.rice.kim.bo.role.dto.KimPermissionTemplateInfo;
28  import org.kuali.rice.kim.bo.role.dto.PermissionAssigneeInfo;
29  import org.kuali.rice.kim.bo.role.dto.RoleMembershipInfo;
30  import org.kuali.rice.kim.bo.role.impl.KimPermissionImpl;
31  import org.kuali.rice.kim.bo.role.impl.KimPermissionTemplateImpl;
32  import org.kuali.rice.kim.bo.types.dto.AttributeDefinitionMap;
33  import org.kuali.rice.kim.dao.KimPermissionDao;
34  import org.kuali.rice.kim.service.KIMServiceLocatorInternal;
35  import org.kuali.rice.kim.service.PermissionService;
36  import org.kuali.rice.kim.service.RoleService;
37  import org.kuali.rice.kim.service.support.KimPermissionTypeService;
38  import org.kuali.rice.kim.util.KIMWebServiceConstants;
39  import org.kuali.rice.kim.util.KimConstants;
40  import org.kuali.rice.kns.datadictionary.AttributeDefinition;
41  import org.kuali.rice.kns.lookup.CollectionIncomplete;
42  import org.kuali.rice.kns.lookup.Lookupable;
43  import org.kuali.rice.kns.service.DataDictionaryService;
44  import org.kuali.rice.kns.service.KNSServiceLocatorWeb;
45  import org.kuali.rice.kns.util.KNSPropertyConstants;
46  
47  import javax.jws.WebService;
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.Collections;
51  import java.util.Comparator;
52  import java.util.HashMap;
53  import java.util.List;
54  import java.util.Map;
55  
56  /**
57   * This is a description of what this class does - jonathan don't forget to fill this in. 
58   * 
59   * @author Kuali Rice Team (rice.collab@kuali.org)
60   *
61   */
62  @WebService(endpointInterface = KIMWebServiceConstants.PermissionService.INTERFACE_CLASS, serviceName = KIMWebServiceConstants.PermissionService.WEB_SERVICE_NAME, portName = KIMWebServiceConstants.PermissionService.WEB_SERVICE_PORT, targetNamespace = KIMWebServiceConstants.MODULE_TARGET_NAMESPACE)
63  public class PermissionServiceImpl extends PermissionServiceBase implements PermissionService {
64  	private static final Logger LOG = Logger.getLogger( PermissionServiceImpl.class );
65  
66     	private RoleService roleService;
67  	private KimPermissionDao permissionDao;
68      private KimPermissionTypeService defaultPermissionTypeService;
69  	
70  	private List<KimPermissionTemplateInfo> allTemplates;
71  	
72      // --------------------
73      // Authorization Checks
74      // --------------------
75      
76  	protected KimPermissionTypeService getPermissionTypeService( String namespaceCode, String permissionTemplateName, String permissionName, String permissionId ) {
77  		StringBuffer cacheKey = new StringBuffer();
78  		if ( namespaceCode != null ) {
79  			cacheKey.append( namespaceCode );
80  		}
81  		cacheKey.append( '|' );
82  		if ( permissionTemplateName != null ) {
83  			cacheKey.append( permissionTemplateName );
84  		}
85  		cacheKey.append( '|' );
86  		if ( permissionName != null ) {
87  			cacheKey.append( permissionName );
88  		}
89  		cacheKey.append( '|' );
90  		if ( permissionId != null ) {
91  			cacheKey.append( permissionId );
92  		}
93  		String key = cacheKey.toString();
94  		KimPermissionTypeService service = getPermissionTypeServiceByNameCache().get(key);
95  		if ( service == null ) {
96  			KimPermissionTemplateImpl permTemplate = null;
97  			if ( permissionTemplateName != null ) {
98  				List<KimPermissionImpl> perms = getPermissionImplsByTemplateName(namespaceCode, permissionTemplateName);
99  				if ( !perms.isEmpty() ) {
100 					permTemplate = perms.get(0).getTemplate();
101 				}
102 			} else if ( permissionName != null ) {
103 				List<KimPermissionImpl> perms = getPermissionImplsByName(namespaceCode, permissionName); 
104 				if ( !perms.isEmpty() ) {
105 					permTemplate = perms.get(0).getTemplate();
106 				}
107 			} else if ( permissionId != null ) {
108 				KimPermissionImpl perm = getPermissionImpl(permissionId);
109 				if ( perm != null ) {
110 					permTemplate = perm.getTemplate();
111 				}
112 			}
113 			service = getPermissionTypeService( permTemplate );
114 			getPermissionTypeServiceByNameCache().put(key, service);
115 		}
116 		return service;
117 	}
118 
119     protected KimPermissionTypeService getPermissionTypeService( KimPermissionTemplateImpl permissionTemplate ) {
120     	if ( permissionTemplate == null ) {
121     		throw new IllegalArgumentException( "permissionTemplate may not be null" );
122     	}
123     	KimType kimType = KimApiServiceLocator.getKimTypeInfoService().getKimType( permissionTemplate.getKimTypeId() );
124     	String serviceName = kimType.getServiceName();
125     	// if no service specified, return a default implementation
126     	if ( StringUtils.isBlank( serviceName ) ) {
127     		return getDefaultPermissionTypeService();
128     	}
129     	try {
130 	    	Object service = KIMServiceLocatorInternal.getService(serviceName);
131 	    	// if we have a service name, it must exist
132 	    	if ( service == null ) {
133 				throw new RuntimeException("null returned for permission type service for service name: " + serviceName);
134 	    	}
135 	    	// whatever we retrieved must be of the correct type
136 	    	if ( !(service instanceof KimPermissionTypeService)  ) {
137 	    		throw new RuntimeException( "Service " + serviceName + " was not a KimPermissionTypeService.  Was: " + service.getClass().getName() );
138 	    	}
139 	    	return (KimPermissionTypeService)service;
140     	} catch( Exception ex ) {
141     		// sometimes service locators throw exceptions rather than returning null, handle that
142     		throw new RuntimeException( "Error retrieving service: " + serviceName + " from the KIMServiceLocatorInternal.", ex );
143     	}
144     }
145     
146     protected KimPermissionTypeService getDefaultPermissionTypeService() {
147     	if ( defaultPermissionTypeService == null ) {
148     		defaultPermissionTypeService = (KimPermissionTypeService) KIMServiceLocatorInternal.getBean(DEFAULT_PERMISSION_TYPE_SERVICE);
149     	}
150 		return defaultPermissionTypeService;
151 	}
152 	
153     /**
154      * @see org.kuali.rice.kim.service.PermissionService#hasPermission(java.lang.String, String, java.lang.String, AttributeSet)
155      */
156     public boolean hasPermission(String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails) {
157     	return isAuthorized( principalId, namespaceCode, permissionName, permissionDetails, null );
158     }
159 
160     /**
161      * @see org.kuali.rice.kim.service.PermissionService#isAuthorized( java.lang.String, String, java.lang.String, AttributeSet, AttributeSet)
162      */
163     public boolean isAuthorized(String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification ) {
164     	List<String> roleIds = getRoleIdsForPermission( namespaceCode, permissionName, permissionDetails );
165     	if ( roleIds.isEmpty() ) {
166     		return false;
167     	}
168 		return getRoleService().principalHasRole( principalId, roleIds, qualification );
169     }
170 
171     /**
172      * @see org.kuali.rice.kim.service.PermissionService#hasPermission(String, String, String, AttributeSet)
173      */
174     public boolean hasPermissionByTemplateName(String principalId, String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails) {
175     	return isAuthorizedByTemplateName( principalId, namespaceCode, permissionTemplateName, permissionDetails, null );
176     }
177 
178     /**
179      * @see org.kuali.rice.kim.service.PermissionService#isAuthorized( java.lang.String, String, java.lang.String, AttributeSet, AttributeSet)
180      */
181     public boolean isAuthorizedByTemplateName(String principalId, String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails, AttributeSet qualification ) {
182     	List<String> roleIds = getRoleIdsForPermissionTemplate( namespaceCode, permissionTemplateName, permissionDetails );
183     	if ( roleIds.isEmpty() ) {
184     		return false;
185     	}
186     	return getRoleService().principalHasRole( principalId, roleIds, qualification );
187     }
188 
189     /**
190      * @see org.kuali.rice.kim.service.PermissionService#getAuthorizedPermissions(String, String, String, AttributeSet, AttributeSet)
191      */
192     public List<KimPermissionInfo> getAuthorizedPermissions( String principalId, String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification ) {
193     	// get all the permission objects whose name match that requested
194     	List<KimPermissionImpl> permissions = getPermissionImplsByName( namespaceCode, permissionName );
195     	// now, filter the full list by the detail passed
196     	List<KimPermissionInfo> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );  
197     	return getPermissionsForUser(principalId, applicablePermissions, qualification);
198     }
199 
200     /**
201      * @see org.kuali.rice.kim.service.PermissionService#getAuthorizedPermissionsByTemplateName(String, String, String, AttributeSet, AttributeSet)
202      */
203     public List<KimPermissionInfo> getAuthorizedPermissionsByTemplateName( String principalId, String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails, AttributeSet qualification ) {
204     	// get all the permission objects whose name match that requested
205     	List<KimPermissionImpl> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
206     	// now, filter the full list by the detail passed
207     	List<KimPermissionInfo> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );  
208     	return getPermissionsForUser(principalId, applicablePermissions, qualification);
209     }
210     
211     /**
212      * Checks the list of permissions against the principal's roles and returns a subset of the list which match.
213      */
214     protected List<KimPermissionInfo> getPermissionsForUser( String principalId, List<KimPermissionInfo> permissions, AttributeSet qualification ) {
215     	ArrayList<KimPermissionInfo> results = new ArrayList<KimPermissionInfo>();
216     	List<KimPermissionInfo> tempList = new ArrayList<KimPermissionInfo>(1);
217     	for ( KimPermissionInfo perm : permissions ) {
218     		tempList.clear();
219     		tempList.add( perm );
220     		List<String> roleIds = permissionDao.getRoleIdsForPermissions( tempList );
221     		// TODO: This could be made a little better by collecting the role IDs into
222     		// a set and then processing the distinct list rather than a check
223     		// for every permission
224     		if ( roleIds != null && !roleIds.isEmpty() ) {
225     			if ( getRoleService().principalHasRole( principalId, roleIds, qualification ) ) {
226     				results.add( perm );
227     			}
228     		}
229     	}
230     	
231     	return results;    	
232     }
233 
234     protected Map<String,KimPermissionTypeService> getPermissionTypeServicesByTemplateId( Collection<KimPermissionImpl> permissions ) {
235     	Map<String,KimPermissionTypeService> permissionTypeServices = new HashMap<String, KimPermissionTypeService>( permissions.size() );
236     	for ( KimPermissionImpl perm : permissions ) {
237     		permissionTypeServices.put(perm.getTemplateId(), getPermissionTypeService( perm.getTemplate() ) );    				
238     	}
239     	return permissionTypeServices;
240     }
241     
242     protected Map<String,List<KimPermissionInfo>> groupPermissionsByTemplate( Collection<KimPermissionImpl> permissions ) {
243     	Map<String,List<KimPermissionInfo>> results = new HashMap<String,List<KimPermissionInfo>>();
244     	for ( KimPermissionImpl perm : permissions ) {
245     		List<KimPermissionInfo> perms = results.get( perm.getTemplateId() );
246     		if ( perms == null ) {
247     			perms = new ArrayList<KimPermissionInfo>();
248     			results.put( perm.getTemplateId(), perms );
249     		}
250     		perms.add( perm.toSimpleInfo() );
251     	}
252     	return results;
253     }
254     
255 	/**
256      * Compare each of the passed in permissions with the given permissionDetails.  Those that
257      * match are added to the result list.
258      */
259     protected List<KimPermissionInfo> getMatchingPermissions( List<KimPermissionImpl> permissions, AttributeSet permissionDetails ) {
260     	List<KimPermissionInfo> applicablePermissions = new ArrayList<KimPermissionInfo>();    	
261     	if ( permissionDetails == null || permissionDetails.isEmpty() ) {
262     		// if no details passed, assume that all match
263     		for ( KimPermissionImpl perm : permissions ) {
264     			applicablePermissions.add( perm.toSimpleInfo() );
265     		}
266     	} else {
267     		// otherwise, attempt to match the permission details
268     		// build a map of the template IDs to the type services
269     		Map<String,KimPermissionTypeService> permissionTypeServices = getPermissionTypeServicesByTemplateId( permissions );
270     		// build a map of permissions by template ID
271     		Map<String,List<KimPermissionInfo>> permissionMap = groupPermissionsByTemplate( permissions );
272     		// loop over the different templates, matching all of the same template against the type
273     		// service at once
274     		for ( String templateId : permissionMap.keySet() ) {
275     			KimPermissionTypeService permissionTypeService = permissionTypeServices.get( templateId );
276     			List<KimPermissionInfo> permissionList = permissionMap.get( templateId );
277 				applicablePermissions.addAll( permissionTypeService.getMatchingPermissions( permissionDetails, permissionList ) );    				
278     		}
279     	}
280     	return applicablePermissions;
281     }
282 
283     /**
284      * @see org.kuali.rice.kim.service.PermissionService#getPermissionAssignees(String, String, AttributeSet, AttributeSet)
285      */
286     public List<PermissionAssigneeInfo> getPermissionAssignees( String namespaceCode, String permissionName, AttributeSet permissionDetails, AttributeSet qualification ) {
287     	List<PermissionAssigneeInfo> results = new ArrayList<PermissionAssigneeInfo>();
288     	List<String> roleIds = getRoleIdsForPermission( namespaceCode, permissionName, permissionDetails);
289     	if ( roleIds.isEmpty() ) {
290     		return results;
291     	}
292     	Collection<RoleMembershipInfo> roleMembers = getRoleService().getRoleMembers( roleIds, qualification );
293     	for ( RoleMembershipInfo rm : roleMembers ) {
294     		if ( rm.getMemberTypeCode().equals( Role.PRINCIPAL_MEMBER_TYPE ) ) {
295     			results.add( new PermissionAssigneeInfo( rm.getMemberId(), null, rm.getDelegates() ) );
296     		} else if ( rm.getMemberTypeCode().equals( Role.GROUP_MEMBER_TYPE ) ) {
297     			results.add( new PermissionAssigneeInfo( null, rm.getMemberId(), rm.getDelegates() ) );
298     		}
299     	}
300     	return results;
301     }
302     
303     public List<PermissionAssigneeInfo> getPermissionAssigneesForTemplateName( String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails, AttributeSet qualification ) {
304     	List<PermissionAssigneeInfo> results = new ArrayList<PermissionAssigneeInfo>();
305     	List<String> roleIds = getRoleIdsForPermissionTemplate( namespaceCode, permissionTemplateName, permissionDetails);
306     	if ( roleIds.isEmpty() ) {
307     		return results;
308     	}
309     	Collection<RoleMembershipInfo> roleMembers = getRoleService().getRoleMembers( roleIds, qualification );
310     	for ( RoleMembershipInfo rm : roleMembers ) {
311     		if ( rm.getMemberTypeCode().equals( Role.PRINCIPAL_MEMBER_TYPE ) ) {
312     			results.add( new PermissionAssigneeInfo( rm.getMemberId(), null, rm.getDelegates() ) );
313     		} else { // a group membership
314     			results.add( new PermissionAssigneeInfo( null, rm.getMemberId(), rm.getDelegates() ) );
315     		}
316     	}
317     	return results;
318     }
319     
320     public boolean isPermissionAssigned( String namespaceCode, String permissionName, AttributeSet permissionDetails ) {
321     	return !getRoleIdsForPermission(namespaceCode, permissionName, permissionDetails).isEmpty();
322     }
323     
324     public boolean isPermissionDefined( String namespaceCode, String permissionName, AttributeSet permissionDetails ) {
325     	// get all the permission objects whose name match that requested
326     	List<KimPermissionImpl> permissions = getPermissionImplsByName( namespaceCode, permissionName );
327     	// now, filter the full list by the detail passed
328     	return !getMatchingPermissions( permissions, permissionDetails ).isEmpty();   
329     }
330     
331     public boolean isPermissionDefinedForTemplateName( String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails ) {
332     	// get all the permission objects whose name match that requested
333     	List<KimPermissionImpl> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
334     	// now, filter the full list by the detail passed
335     	return !getMatchingPermissions( permissions, permissionDetails ).isEmpty();   
336     }
337  
338     public List<String> getRoleIdsForPermission( String namespaceCode, String permissionName, AttributeSet permissionDetails) {
339     	// get all the permission objects whose name match that requested
340     	List<KimPermissionImpl> permissions = getPermissionImplsByName( namespaceCode, permissionName );
341     	// now, filter the full list by the detail passed
342     	List<KimPermissionInfo> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );    	
343     	List<String> roleIds = getRolesForPermissionsFromCache( applicablePermissions );
344     	if ( roleIds == null ) {
345     		roleIds = permissionDao.getRoleIdsForPermissions( applicablePermissions );
346     		addRolesForPermissionsToCache( applicablePermissions, roleIds );
347     	}
348     	return roleIds;    	
349     }
350 
351     protected List<String> getRoleIdsForPermissionTemplate( String namespaceCode, String permissionTemplateName, AttributeSet permissionDetails ) {
352     	// get all the permission objects whose name match that requested
353     	List<KimPermissionImpl> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
354     	// now, filter the full list by the detail passed
355     	List<KimPermissionInfo> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );
356     	List<String> roleIds = getRolesForPermissionsFromCache( applicablePermissions );
357     	if ( roleIds == null ) {
358     		roleIds = permissionDao.getRoleIdsForPermissions( applicablePermissions );
359     		addRolesForPermissionsToCache( applicablePermissions, roleIds );
360     	}
361     	return roleIds;
362     }
363     
364     public List<String> getRoleIdsForPermissions( List<KimPermissionInfo> permissions ) {
365     	List<String> roleIds = getRolesForPermissionsFromCache( permissions );
366     	if ( roleIds == null ) {
367     		roleIds = permissionDao.getRoleIdsForPermissions( permissions );
368     		addRolesForPermissionsToCache( permissions, roleIds );
369     	}
370     	return roleIds;
371     }
372 
373     // --------------------
374     // Permission Data
375     // --------------------
376     
377     /**
378      * @see org.kuali.rice.kim.service.PermissionService#getPermission(java.lang.String)
379      */
380     public KimPermissionInfo getPermission(String permissionId) {
381     	KimPermissionImpl impl = getPermissionImpl( permissionId );
382     	if ( impl != null ) {
383     		return impl.toSimpleInfo();
384     	}
385     	return null;
386     }
387     
388     /**
389      * @see org.kuali.rice.kim.service.PermissionService#getPermissionsByTemplateName(String, String)
390      */
391     public List<KimPermissionInfo> getPermissionsByTemplateName(String namespaceCode, String permissionTemplateName) {
392     	List<KimPermissionImpl> impls = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
393     	List<KimPermissionInfo> results = new ArrayList<KimPermissionInfo>( impls.size() );
394     	for ( KimPermissionImpl impl : impls ) {
395     		results.add( impl.toSimpleInfo() );
396     	}
397     	return results;
398     }
399 
400 	/**
401      * @see org.kuali.rice.kim.service.PermissionService#getPermissionsByName(String, String)
402      */
403     public List<KimPermissionInfo> getPermissionsByName(String namespaceCode, String permissionName) {
404     	List<KimPermissionImpl> impls = getPermissionImplsByName( namespaceCode, permissionName );
405     	List<KimPermissionInfo> results = new ArrayList<KimPermissionInfo>( impls.size() );
406     	for ( KimPermissionImpl impl : impls ) {
407     		results.add( impl.toSimpleInfo() );
408     	}
409     	return results;
410     }
411     
412     @SuppressWarnings("unchecked")
413 	protected KimPermissionImpl getPermissionImpl(String permissionId) {
414     	if ( StringUtils.isBlank( permissionId ) ) {
415     		return null;
416     	}
417     	String cacheKey = getPermissionImplByIdCacheKey(permissionId);
418     	List<KimPermissionImpl> permissions = (List<KimPermissionImpl>)getCacheAdministrator().getFromCache(cacheKey, getRefreshPeriodInSeconds());
419     	if ( permissions == null ) {
420 	    	HashMap<String,Object> pk = new HashMap<String,Object>( 1 );
421 	    	pk.put( KimConstants.PrimaryKeyConstants.PERMISSION_ID, permissionId );
422 	    	permissions = Collections.singletonList( (KimPermissionImpl)getBusinessObjectService().findByPrimaryKey( KimPermissionImpl.class, pk ) );
423 	    	getCacheAdministrator().putInCache(cacheKey, permissions, PERMISSION_IMPL_CACHE_GROUP);
424     	}
425     	return permissions.get( 0 );
426     }
427     
428     @SuppressWarnings("unchecked")
429 	protected List<KimPermissionImpl> getPermissionImplsByTemplateName( String namespaceCode, String permissionTemplateName ) {
430     	String cacheKey = getPermissionImplByTemplateNameCacheKey(namespaceCode, permissionTemplateName);
431     	List<KimPermissionImpl> permissions = (List<KimPermissionImpl>)getCacheAdministrator().getFromCache(cacheKey, getRefreshPeriodInSeconds());
432     	if ( permissions == null ) {    	
433 	    	HashMap<String,Object> pk = new HashMap<String,Object>( 3 );
434 	    	pk.put( "template.namespaceCode", namespaceCode );
435 	    	pk.put( "template.name", permissionTemplateName );
436 			pk.put( KNSPropertyConstants.ACTIVE, "Y" );
437 	    	permissions = (List<KimPermissionImpl>)getBusinessObjectService().findMatching( KimPermissionImpl.class, pk );
438 	    	getCacheAdministrator().putInCache(cacheKey, permissions, PERMISSION_IMPL_CACHE_GROUP);
439     	}
440     	return permissions;
441     }
442 
443     @SuppressWarnings("unchecked")
444 	protected List<KimPermissionImpl> getPermissionImplsByName( String namespaceCode, String permissionName ) {
445     	String cacheKey = getPermissionImplByNameCacheKey(namespaceCode, permissionName);
446     	List<KimPermissionImpl> permissions = (List<KimPermissionImpl>)getCacheAdministrator().getFromCache(cacheKey, getRefreshPeriodInSeconds());
447     	if ( permissions == null ) {
448 	    	HashMap<String,Object> pk = new HashMap<String,Object>( 3 );
449 	    	pk.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode );
450 	    	pk.put( KimConstants.UniqueKeyConstants.PERMISSION_NAME, permissionName );
451 			pk.put( KNSPropertyConstants.ACTIVE, "Y" );
452 	    	permissions = (List<KimPermissionImpl>)getBusinessObjectService().findMatching( KimPermissionImpl.class, pk );
453 	    	getCacheAdministrator().putInCache(cacheKey, permissions, PERMISSION_IMPL_CACHE_GROUP);
454     	}
455     	return permissions;
456     }
457 
458     
459     
460     // --------------------
461     // Support Methods
462     // --------------------
463 	
464 	
465 	protected RoleService getRoleService() {
466 		if ( roleService == null ) {
467 			roleService = KimApiServiceLocator.getRoleManagementService();
468 		}
469 
470 		return roleService;
471 	}
472 
473 	public void setRoleService(RoleService roleService) {
474 		this.roleService = roleService;
475 	}
476 
477 	public KimPermissionDao getPermissionDao() {
478 		return this.permissionDao;
479 	}
480 
481 	public void setPermissionDao(KimPermissionDao permissionDao) {
482 		this.permissionDao = permissionDao;
483 	}
484 
485 	@SuppressWarnings("unchecked")
486 	public List<KimPermissionInfo> lookupPermissions(Map<String, String> searchCriteria, boolean unbounded ){
487 		Collection baseResults = null;
488 		Lookupable permissionLookupable = KNSServiceLocatorWeb.getLookupable(
489                 KNSServiceLocatorWeb.getBusinessObjectDictionaryService().getLookupableID(PermissionImpl.class)
490         );
491 		permissionLookupable.setBusinessObjectClass(PermissionImpl.class);
492 		if ( unbounded ) {
493 		    baseResults = permissionLookupable.getSearchResultsUnbounded( searchCriteria );
494 		} else {
495 			baseResults = permissionLookupable.getSearchResults(searchCriteria);
496 		}
497 		List<KimPermissionInfo> results = new ArrayList<KimPermissionInfo>( baseResults.size() );
498 		for ( KimPermissionImpl resp : (Collection<PermissionImpl>)baseResults ) {
499 			results.add( resp.toSimpleInfo() );
500 		}
501 		if ( baseResults instanceof CollectionIncomplete ) {
502 			results = new CollectionIncomplete<KimPermissionInfo>( results, ((CollectionIncomplete<KimPermissionInfo>)baseResults).getActualSizeIfTruncated() ); 
503 		}		
504 		return results;
505 	}
506 
507 	public String getPermissionDetailLabel( String permissionId, String kimTypeId, String attributeName) {
508     	// get the type service for this permission
509 		KimPermissionTypeService typeService = getPermissionTypeService(null, null, null, permissionId);
510 		if ( typeService != null ) {
511 			// ask the type service for the attribute definition for the given attribute name
512 			AttributeDefinitionMap attributes = typeService.getAttributeDefinitions( kimTypeId );
513 			String label = null;
514 			for ( AttributeDefinition attributeDef : attributes.values() ) {
515 				if ( attributeDef.getName().equals(attributeName) ) {
516 					label = attributeDef.getLabel();
517 				}
518 			}
519 			// return the attribute label
520 			if ( label != null ) {
521 				return label;
522 			} else {
523 				return "Missing Def: " + attributeName;
524 			}
525 		} else {
526 			return "No Label: " + attributeName;
527 		}
528 	}
529 	
530 	/**
531 	 * @see org.kuali.rice.kim.service.PermissionService#getPermissionTemplate(java.lang.String)
532 	 */
533 	public KimPermissionTemplateInfo getPermissionTemplate(String permissionTemplateId) {
534 		KimPermissionTemplateImpl impl = getBusinessObjectService().findBySinglePrimaryKey( KimPermissionTemplateImpl.class, permissionTemplateId );
535 		if ( impl != null ) {
536 			return impl.toSimpleInfo();
537 		}
538 		return null;
539 	}
540 
541 	/**
542 	 * This overridden method ...
543 	 * 
544 	 * @see org.kuali.rice.kim.service.PermissionService#getPermissionTemplateByName(java.lang.String, java.lang.String)
545 	 */
546 	public KimPermissionTemplateInfo getPermissionTemplateByName(String namespaceCode,
547 			String permissionTemplateName) {
548 		Map<String,String> criteria = new HashMap<String,String>(2);
549 		criteria.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode );
550 		criteria.put( KimConstants.UniqueKeyConstants.PERMISSION_TEMPLATE_NAME, permissionTemplateName );
551 		KimPermissionTemplateImpl impl = (KimPermissionTemplateImpl)getBusinessObjectService().findByPrimaryKey( KimPermissionTemplateImpl.class, criteria );
552 		if ( impl != null ) {
553 			return impl.toSimpleInfo();
554 		}
555 		return null;
556 	}
557 	
558 	@SuppressWarnings("unchecked")
559 	public List<KimPermissionTemplateInfo> getAllTemplates() {
560 		if ( allTemplates == null ) {
561 			Map<String,String> criteria = new HashMap<String,String>(1);
562 			criteria.put( KNSPropertyConstants.ACTIVE, "Y" );
563 			List<KimPermissionTemplateImpl> impls = (List<KimPermissionTemplateImpl>)getBusinessObjectService().findMatching( KimPermissionTemplateImpl.class, criteria );
564 			List<KimPermissionTemplateInfo> infos = new ArrayList<KimPermissionTemplateInfo>( impls.size() );
565 			for ( KimPermissionTemplateImpl impl : impls ) {
566 				infos.add( impl.toSimpleInfo() );
567 			}
568 			Collections.sort(infos, new Comparator<KimPermissionTemplateInfo>() {
569 				public int compare(KimPermissionTemplateInfo tmpl1,
570 						KimPermissionTemplateInfo tmpl2) {
571 					int result = 0;
572 					result = tmpl1.getNamespaceCode().compareTo(tmpl2.getNamespaceCode());
573 					if ( result != 0 ) {
574 						return result;
575 					}
576 					result = tmpl1.getName().compareTo(tmpl2.getName());
577 					return result;
578 				}
579 			});
580 			allTemplates = infos;
581 		}
582 		return allTemplates;
583 	}
584 
585     
586 	
587 	private DataDictionaryService dataDictionaryService;
588 	protected DataDictionaryService getDataDictionaryService() {
589 		if(dataDictionaryService == null){
590 			dataDictionaryService = KNSServiceLocatorWeb.getDataDictionaryService();
591 		}
592 		return dataDictionaryService;
593 	}
594 	
595 
596     public List<String> getRoleIdsForPermissionId(String permissionId) {
597         KimPermissionInfo permissionInfo = getPermission(permissionId);
598 
599         List<KimPermissionInfo> applicablePermissions = new ArrayList<KimPermissionInfo>();
600         applicablePermissions.add(permissionInfo);
601 
602         List<String> roleIds = getRolesForPermissionsFromCache(applicablePermissions);
603         if (roleIds == null) {
604             roleIds = permissionDao.getRoleIdsForPermissions(applicablePermissions);
605             addRolesForPermissionsToCache(applicablePermissions, roleIds);
606         }
607 
608         return roleIds;
609     }
610 
611     public List<KimPermissionInfo> getPermissionsByNameIncludingInactive(String namespaceCode, String permissionName) {
612         List<KimPermissionImpl> impls = getPermissionImplsByNameIncludingInactive(namespaceCode, permissionName);
613         List<KimPermissionInfo> results = new ArrayList<KimPermissionInfo>(impls.size());
614         for (KimPermissionImpl impl : impls) {
615             results.add(impl.toSimpleInfo());
616         }
617         return results;
618     }
619 	
620     @SuppressWarnings("unchecked")
621     protected List<KimPermissionImpl> getPermissionImplsByNameIncludingInactive(String namespaceCode, String permissionName) {
622         String cacheKey = getPermissionImplByNameCacheKey(namespaceCode, permissionName + "inactive");
623         List<KimPermissionImpl> permissions = (List<KimPermissionImpl>) getCacheAdministrator().getFromCache(cacheKey, getRefreshPeriodInSeconds());
624         if (permissions == null) {
625             HashMap<String, Object> pk = new HashMap<String, Object>(2);
626             pk.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode);
627             pk.put(KimConstants.UniqueKeyConstants.PERMISSION_NAME, permissionName);
628             permissions = (List<KimPermissionImpl>) getBusinessObjectService().findMatching(KimPermissionImpl.class, pk);
629             getCacheAdministrator().putInCache(cacheKey, permissions, PERMISSION_IMPL_CACHE_GROUP);
630         }
631         return permissions;
632     }
633     
634     public int getRefreshPeriodInSeconds() {
635         try {
636             return (int)(new Integer(ConfigContext.getCurrentContextConfig().getProperty(KimConstants.CacheRefreshPeriodSeconds.KIM_CACHE_PERMISSION_REFRESH_PERIOD_SECONDS)));
637         } catch (NumberFormatException e) {
638     		// The cache will never expire when refreshPeriod is set to -1
639     		return -1;        		
640         }
641     }
642 }