View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kim.impl.permission;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.criteria.CriteriaLookupService;
21  import org.kuali.rice.core.api.criteria.GenericQueryResults;
22  import org.kuali.rice.core.api.criteria.LookupCustomizer;
23  import org.kuali.rice.core.api.criteria.QueryByCriteria;
24  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
25  import org.kuali.rice.core.api.exception.RiceIllegalStateException;
26  import org.kuali.rice.core.api.membership.MemberType;
27  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
28  import org.kuali.rice.kim.api.KimConstants;
29  import org.kuali.rice.kim.api.common.assignee.Assignee;
30  import org.kuali.rice.kim.api.common.delegate.DelegateType;
31  import org.kuali.rice.kim.api.common.template.Template;
32  import org.kuali.rice.kim.api.common.template.TemplateQueryResults;
33  import org.kuali.rice.kim.api.permission.Permission;
34  import org.kuali.rice.kim.api.permission.PermissionQueryResults;
35  import org.kuali.rice.kim.api.permission.PermissionService;
36  import org.kuali.rice.kim.api.role.Role;
37  import org.kuali.rice.kim.api.role.RoleMembership;
38  import org.kuali.rice.kim.api.role.RoleService;
39  import org.kuali.rice.kim.api.type.KimType;
40  import org.kuali.rice.kim.api.type.KimTypeInfoService;
41  import org.kuali.rice.kim.framework.permission.PermissionTypeService;
42  import org.kuali.rice.kim.impl.common.attribute.AttributeTransform;
43  import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo;
44  import org.kuali.rice.kim.impl.role.RolePermissionBo;
45  import org.kuali.rice.krad.service.BusinessObjectService;
46  import org.kuali.rice.krad.util.KRADPropertyConstants;
47  
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  import java.util.concurrent.CopyOnWriteArrayList;
56  
57  import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
58  
59  public class PermissionServiceImpl implements PermissionService {
60  	private RoleService roleService;
61      private PermissionTypeService defaultPermissionTypeService;
62      private KimTypeInfoService kimTypeInfoService;
63  	private BusinessObjectService businessObjectService;
64  	private CriteriaLookupService criteriaLookupService;
65  
66   	private final CopyOnWriteArrayList<Template> allTemplates = new CopyOnWriteArrayList<Template>();
67  
68      // --------------------
69      // Authorization Checks
70      // --------------------
71  
72      protected PermissionTypeService getPermissionTypeService( PermissionTemplateBo permissionTemplate ) {
73      	if ( permissionTemplate == null ) {
74      		throw new IllegalArgumentException( "permissionTemplate may not be null" );
75      	}
76      	KimType kimType = kimTypeInfoService.getKimType( permissionTemplate.getKimTypeId() );
77      	String serviceName = kimType.getServiceName();
78      	// if no service specified, return a default implementation
79      	if ( StringUtils.isBlank( serviceName ) ) {
80      		return defaultPermissionTypeService;
81      	}
82      	try {
83  	    	Object service = GlobalResourceLoader.getService(serviceName);
84  	    	// if we have a service name, it must exist
85  	    	if ( service == null ) {
86  				throw new RuntimeException("null returned for permission type service for service name: " + serviceName);
87  	    	}
88  	    	// whatever we retrieved must be of the correct type
89  	    	if ( !(service instanceof PermissionTypeService)  ) {
90  	    		throw new RuntimeException( "Service " + serviceName + " was not a PermissionTypeService.  Was: " + service.getClass().getName() );
91  	    	}
92  	    	return (PermissionTypeService)service;
93      	} catch( Exception ex ) {
94      		// sometimes service locators throw exceptions rather than returning null, handle that
95      		throw new RuntimeException( "Error retrieving service: " + serviceName + " from the KimImplServiceLocator.", ex );
96      	}
97      }
98  
99      @Override
100     public boolean hasPermission(String principalId, String namespaceCode,
101                                  String permissionName, Map<String, String> permissionDetails) throws RiceIllegalArgumentException  {
102         incomingParamCheck(principalId, "principalId");
103         incomingParamCheck(namespaceCode, "namespaceCode");
104         incomingParamCheck(permissionName, "permissionName");
105         incomingParamCheck(permissionDetails, "permissionDetails");
106 
107         return isAuthorized( principalId, namespaceCode, permissionName, permissionDetails, Collections.<String, String>emptyMap() );
108     }
109 
110     @Override
111     public boolean isAuthorized(String principalId, String namespaceCode,
112                                 String permissionName, Map<String, String> permissionDetails,
113                                 Map<String, String> qualification ) throws RiceIllegalArgumentException {
114         incomingParamCheck(principalId, "principalId");
115         incomingParamCheck(namespaceCode, "namespaceCode");
116         incomingParamCheck(permissionName, "permissionName");
117         incomingParamCheck(permissionDetails, "permissionDetails");
118         incomingParamCheck(qualification, "qualification");
119 
120         List<String> roleIds = getRoleIdsForPermission( namespaceCode, permissionName, permissionDetails );
121     	if ( roleIds.isEmpty() ) {
122     		return false;
123     	}
124 
125 		return roleService.principalHasRole( principalId, roleIds, qualification);
126 
127     }
128     @Override
129     public boolean hasPermissionByTemplateName(String principalId, String namespaceCode,
130             String permissionTemplateName, Map<String, String> permissionDetails) throws RiceIllegalArgumentException {
131         incomingParamCheck(principalId, "principalId");
132         incomingParamCheck(namespaceCode, "namespaceCode");
133         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
134         incomingParamCheck(permissionDetails, "permissionDetails");
135 
136         return isAuthorizedByTemplateName( principalId, namespaceCode, permissionTemplateName, permissionDetails, Collections.<String, String>emptyMap() );
137     }
138     @Override
139     public boolean isAuthorizedByTemplateName(String principalId, String namespaceCode,
140                                               String permissionTemplateName, Map<String, String> permissionDetails,
141                                               Map<String, String> qualification ) throws RiceIllegalArgumentException {
142         incomingParamCheck(principalId, "principalId");
143         incomingParamCheck(namespaceCode, "namespaceCode");
144         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
145         incomingParamCheck(permissionDetails, "permissionDetails");
146         incomingParamCheck(qualification, "qualification");
147 
148         List<String> roleIds = getRoleIdsForPermissionTemplate( namespaceCode, permissionTemplateName, permissionDetails );
149     	if ( roleIds.isEmpty() ) {
150     		return false;
151     	}
152     	return roleService.principalHasRole( principalId, roleIds, qualification);
153     }
154     @Override
155     public List<Permission> getAuthorizedPermissions( String principalId,
156             String namespaceCode, String permissionName, Map<String, String> permissionDetails,
157             Map<String, String> qualification ) throws RiceIllegalArgumentException {
158         incomingParamCheck(principalId, "principalId");
159         incomingParamCheck(namespaceCode, "namespaceCode");
160         incomingParamCheck(permissionName, "permissionName");
161         incomingParamCheck(permissionDetails, "permissionDetails");
162         incomingParamCheck(qualification, "qualification");
163 
164         // get all the permission objects whose name match that requested
165     	List<PermissionBo> permissions = getPermissionImplsByName( namespaceCode, permissionName );
166     	// now, filter the full list by the detail passed
167     	List<Permission> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );
168     	return getPermissionsForUser(principalId, applicablePermissions, qualification);
169     }
170     @Override
171     public List<Permission> getAuthorizedPermissionsByTemplateName( String principalId, String namespaceCode,
172             String permissionTemplateName, Map<String, String> permissionDetails,
173             Map<String, String> qualification ) throws RiceIllegalArgumentException {
174         incomingParamCheck(principalId, "principalId");
175         incomingParamCheck(namespaceCode, "namespaceCode");
176         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
177         incomingParamCheck(permissionDetails, "permissionDetails");
178         incomingParamCheck(qualification, "qualification");
179 
180         // get all the permission objects whose name match that requested
181     	List<PermissionBo> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
182     	// now, filter the full list by the detail passed
183     	List<Permission> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );
184     	return getPermissionsForUser(principalId, applicablePermissions, qualification);
185     }
186     
187     /**
188      * Checks the list of permissions against the principal's roles and returns a subset of the list which match.
189      */
190     protected List<Permission> getPermissionsForUser( String principalId, List<Permission> permissions,
191             Map<String, String> qualification ) {
192     	ArrayList<Permission> results = new ArrayList<Permission>();
193     	List<Permission> tempList = new ArrayList<Permission>(1);
194     	for ( Permission perm : permissions ) {
195     		tempList.clear();
196     		tempList.add( perm );
197     		List<String> roleIds = getRoleIdsForPermissions( tempList );
198     		// TODO: This could be made a little better by collecting the role IDs into
199     		// a set and then processing the distinct list rather than a check
200     		// for every permission
201     		if ( roleIds != null && !roleIds.isEmpty() ) {
202     			if ( roleService.principalHasRole( principalId, roleIds, qualification) ) {
203     				results.add( perm );
204     			}
205     		}
206     	}
207     	
208     	return Collections.unmodifiableList(results);
209     }
210 
211     protected Map<String,PermissionTypeService> getPermissionTypeServicesByTemplateId( Collection<PermissionBo> permissions ) {
212     	Map<String,PermissionTypeService> permissionTypeServices = new HashMap<String, PermissionTypeService>( permissions.size() );
213     	for ( PermissionBo perm : permissions ) {
214     		permissionTypeServices.put(perm.getTemplateId(), getPermissionTypeService( perm.getTemplate() ) );    				
215     	}
216     	return permissionTypeServices;
217     }
218     
219     @SuppressWarnings("static-access")
220 	protected Map<String,List<Permission>> groupPermissionsByTemplate( Collection<PermissionBo> permissions ) {
221     	Map<String,List<Permission>> results = new HashMap<String,List<Permission>>();
222     	for ( PermissionBo perm : permissions ) {
223     		List<Permission> perms = results.get( perm.getTemplateId() );
224     		if ( perms == null ) {
225     			perms = new ArrayList<Permission>();
226     			results.put( perm.getTemplateId(), perms );
227     		}
228     		perms.add( PermissionBo.to(perm) );
229     	}
230     	return results;
231     }
232     
233 	/**
234      * Compare each of the passed in permissions with the given permissionDetails.  Those that
235      * match are added to the result list.
236      */
237     protected List<Permission> getMatchingPermissions( List<PermissionBo> permissions, Map<String, String> permissionDetails ) {
238     	List<Permission> applicablePermissions = new ArrayList<Permission>();    	
239     	if ( permissionDetails == null || permissionDetails.isEmpty() ) {
240     		// if no details passed, assume that all match
241     		for ( PermissionBo perm : permissions ) {
242     			applicablePermissions.add( PermissionBo.to(perm) );
243     		}
244     	} else {
245     		// otherwise, attempt to match the permission details
246     		// build a map of the template IDs to the type services
247     		Map<String,PermissionTypeService> permissionTypeServices = getPermissionTypeServicesByTemplateId( permissions );
248     		// build a map of permissions by template ID
249     		Map<String,List<Permission>> permissionMap = groupPermissionsByTemplate( permissions );
250     		// loop over the different templates, matching all of the same template against the type
251     		// service at once
252     		for ( Map.Entry<String,List<Permission>> entry : permissionMap.entrySet() ) {
253     			PermissionTypeService permissionTypeService = permissionTypeServices.get( entry.getKey() );
254     			List<Permission> permissionList = entry.getValue();
255 				applicablePermissions.addAll( permissionTypeService.getMatchingPermissions( permissionDetails, permissionList ) );    				
256     		}
257     	}
258     	return applicablePermissions;
259     }
260     @Override
261     public List<Assignee> getPermissionAssignees( String namespaceCode, String permissionName,
262             Map<String, String> permissionDetails, Map<String, String> qualification ) throws RiceIllegalArgumentException {
263         incomingParamCheck(namespaceCode, "namespaceCode");
264         incomingParamCheck(permissionName, "permissionName");
265         incomingParamCheck(permissionDetails, "permissionDetails");
266         incomingParamCheck(qualification, "qualification");
267 
268 
269     	List<String> roleIds = getRoleIdsForPermission( namespaceCode, permissionName, permissionDetails);
270     	if ( roleIds.isEmpty() ) {
271     		return Collections.emptyList();
272     	}
273     	Collection<RoleMembership> roleMembers = roleService.getRoleMembers( roleIds,qualification );
274     	List<Assignee> results = new ArrayList<Assignee>();
275         for ( RoleMembership rm : roleMembers ) {
276 			List<DelegateType.Builder> delegateBuilderList = new ArrayList<DelegateType.Builder>();
277 			if (!rm.getDelegates().isEmpty()) {
278     			for (DelegateType delegate : rm.getDelegates()){
279                     delegateBuilderList.add(DelegateType.Builder.create(delegate));
280     			}
281 			}
282     		if ( MemberType.PRINCIPAL.equals(rm.getMemberType()) ) {
283     			results.add (Assignee.Builder.create(rm.getMemberId(), null, delegateBuilderList).build());
284     		} else if ( MemberType.GROUP.equals(rm.getMemberType()) ) {
285     			results.add (Assignee.Builder.create(null, rm.getMemberId(), delegateBuilderList).build());
286     		}
287     	}
288     	return Collections.unmodifiableList(results);
289     }
290 
291     @Override
292     public List<Assignee> getPermissionAssigneesByTemplateName(String namespaceCode, String permissionTemplateName,
293             Map<String, String> permissionDetails, Map<String, String> qualification) throws RiceIllegalArgumentException {
294         incomingParamCheck(namespaceCode, "namespaceCode");
295         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
296         incomingParamCheck(permissionDetails, "permissionDetails");
297         incomingParamCheck(qualification, "qualification");
298 
299     	List<String> roleIds = getRoleIdsForPermissionTemplate( namespaceCode, permissionTemplateName, permissionDetails);
300     	if ( roleIds.isEmpty() ) {
301     		return Collections.emptyList();
302     	}
303     	Collection<RoleMembership> roleMembers = roleService.getRoleMembers( roleIds,qualification);
304     	List<Assignee> results = new ArrayList<Assignee>();
305         for ( RoleMembership rm : roleMembers ) {
306 			List<DelegateType.Builder> delegateBuilderList = new ArrayList<DelegateType.Builder>();
307 			if (!rm.getDelegates().isEmpty()) {
308     			for (DelegateType delegate : rm.getDelegates()){
309                     delegateBuilderList.add(DelegateType.Builder.create(delegate));
310     			}
311 			}
312     		if ( MemberType.PRINCIPAL.equals(rm.getMemberType()) ) {
313     			results.add (Assignee.Builder.create(rm.getMemberId(), null, delegateBuilderList).build());
314     		} else { // a group membership
315     			results.add (Assignee.Builder.create(null, rm.getMemberId(), delegateBuilderList).build());
316     		}
317     	}
318     	return Collections.unmodifiableList(results);
319     }
320 
321     @Override
322     public boolean isPermissionDefined( String namespaceCode, String permissionName,
323              Map<String, String> permissionDetails ) throws RiceIllegalArgumentException {
324         incomingParamCheck(namespaceCode, "namespaceCode");
325         incomingParamCheck(permissionName, "permissionName");
326         incomingParamCheck(permissionDetails, "permissionDetails");
327 
328     	// get all the permission objects whose name match that requested
329     	List<PermissionBo> permissions = getPermissionImplsByName( namespaceCode, permissionName );
330     	// now, filter the full list by the detail passed
331     	return !getMatchingPermissions( permissions, permissionDetails ).isEmpty();
332     }
333 
334     @Override
335     public boolean isPermissionDefinedByTemplateName(String namespaceCode, String permissionTemplateName,
336             Map<String, String> permissionDetails) throws RiceIllegalArgumentException {
337 
338         incomingParamCheck(namespaceCode, "namespaceCode");
339         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
340         incomingParamCheck(permissionDetails, "permissionDetails");
341 
342     	// get all the permission objects whose name match that requested
343     	List<PermissionBo> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
344     	// now, filter the full list by the detail passed
345     	return !getMatchingPermissions( permissions, permissionDetails ).isEmpty();
346     }
347 
348     @Override
349     public List<String> getRoleIdsForPermission(String namespaceCode, String permissionName,
350             Map<String, String> permissionDetails) throws RiceIllegalArgumentException {
351         incomingParamCheck(namespaceCode, "namespaceCode");
352         incomingParamCheck(permissionName, "permissionName");
353         incomingParamCheck(permissionDetails, "permissionDetails");
354 
355         // get all the permission objects whose name match that requested
356         List<PermissionBo> permissions = getPermissionImplsByName(namespaceCode, permissionName);
357         // now, filter the full list by the detail passed
358         List<Permission> applicablePermissions = getMatchingPermissions(permissions, permissionDetails);
359         return getRoleIdsForPermissions(applicablePermissions);
360     }
361 
362     protected List<String> getRoleIdsForPermissionTemplate( String namespaceCode, String permissionTemplateName, Map<String, String> permissionDetails ) {
363     	// get all the permission objects whose name match that requested
364     	List<PermissionBo> permissions = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
365     	// now, filter the full list by the detail passed
366     	List<Permission> applicablePermissions = getMatchingPermissions( permissions, permissionDetails );
367     	return getRoleIdsForPermissions( applicablePermissions );
368     }
369 
370     // --------------------
371     // Permission Data
372     // --------------------
373     
374     @Override
375     public Permission getPermission(String permissionId) throws RiceIllegalArgumentException {
376         incomingParamCheck(permissionId, "permissionId");
377 
378         PermissionBo impl = getPermissionImpl( permissionId );
379     	if ( impl != null ) {
380     		return PermissionBo.to(impl);
381     	}
382     	return null;
383     }
384     
385     @Override
386     public List<Permission> findPermsByNamespaceCodeTemplateName(String namespaceCode,
387             String permissionTemplateName) throws RiceIllegalArgumentException {
388         incomingParamCheck(namespaceCode, "namespaceCode");
389         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
390 
391         List<PermissionBo> impls = getPermissionImplsByTemplateName( namespaceCode, permissionTemplateName );
392     	List<Permission> results = new ArrayList<Permission>(impls.size());
393     	for (PermissionBo impl : impls) {
394     	    results.add(PermissionBo.to(impl));
395     	}
396     	return Collections.unmodifiableList(results);
397     }
398 
399 	protected PermissionBo getPermissionImpl(String permissionId) throws RiceIllegalArgumentException {
400     	incomingParamCheck(permissionId, "permissionId");
401 
402         HashMap<String,Object> pk = new HashMap<String,Object>( 1 );
403         pk.put( KimConstants.PrimaryKeyConstants.PERMISSION_ID, permissionId );
404         return businessObjectService.findByPrimaryKey( PermissionBo.class, pk );
405     }
406     
407     protected List<PermissionBo> getPermissionImplsByTemplateName( String namespaceCode, String permissionTemplateName ){
408         HashMap<String,Object> pk = new HashMap<String,Object>( 3 );
409         pk.put( "template.namespaceCode", namespaceCode );
410         pk.put( "template.name", permissionTemplateName );
411         pk.put( KRADPropertyConstants.ACTIVE, "Y" );
412         return ((List<PermissionBo>) businessObjectService.findMatching( PermissionBo.class, pk ));
413     }
414 
415     protected List<PermissionBo> getPermissionImplsByName( String namespaceCode, String permissionName ) {
416         HashMap<String,Object> pk = new HashMap<String,Object>( 3 );
417         pk.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode );
418         pk.put( KimConstants.UniqueKeyConstants.PERMISSION_NAME, permissionName );
419         pk.put( KRADPropertyConstants.ACTIVE, "Y" );
420         
421         return ((List<PermissionBo>) businessObjectService.findMatching( PermissionBo.class, pk ));
422     }
423 	
424     @Override
425 	public Template getPermissionTemplate(String permissionTemplateId) throws RiceIllegalArgumentException {
426         incomingParamCheck(permissionTemplateId, "permissionTemplateId");
427 
428         PermissionTemplateBo impl = businessObjectService.findBySinglePrimaryKey( PermissionTemplateBo.class, permissionTemplateId );
429 		if ( impl != null ) {
430 			return PermissionTemplateBo.to(impl);
431 		}
432 		return null;
433 	}
434 
435     @Override
436 	public Template findPermTemplateByNamespaceCodeAndName(String namespaceCode,
437             String permissionTemplateName) throws RiceIllegalArgumentException {
438 		incomingParamCheck(namespaceCode, "namespaceCode");
439         incomingParamCheck(permissionTemplateName, "permissionTemplateName");
440 
441         Map<String,String> criteria = new HashMap<String,String>(2);
442 		criteria.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode );
443 		criteria.put( KimConstants.UniqueKeyConstants.PERMISSION_TEMPLATE_NAME, permissionTemplateName );
444 		PermissionTemplateBo impl = businessObjectService.findByPrimaryKey( PermissionTemplateBo.class, criteria );
445 		if ( impl != null ) {
446 			return PermissionTemplateBo.to(impl);
447 		}
448 		return null;
449 	}
450 
451     @Override
452 	public List<Template> getAllTemplates() {
453 		if ( allTemplates.isEmpty() ) {
454 			Map<String,String> criteria = new HashMap<String,String>(1);
455 			criteria.put( KRADPropertyConstants.ACTIVE, "Y" );
456 			List<PermissionTemplateBo> impls = (List<PermissionTemplateBo>) businessObjectService.findMatching( PermissionTemplateBo.class, criteria );
457 			List<Template> infos = new ArrayList<Template>( impls.size() );
458 			for ( PermissionTemplateBo impl : impls ) {
459 				infos.add( PermissionTemplateBo.to(impl) );
460 			}
461 			Collections.sort(infos, new Comparator<Template>() {
462 				@Override public int compare(Template tmpl1,
463 						Template tmpl2) {
464 
465 					int result = tmpl1.getNamespaceCode().compareTo(tmpl2.getNamespaceCode());
466 					if ( result != 0 ) {
467 						return result;
468 					}
469 					result = tmpl1.getName().compareTo(tmpl2.getName());
470 					return result;
471 				}
472 			});
473 			allTemplates.addAll(infos);
474 		}
475 		return Collections.unmodifiableList(allTemplates);
476     }
477 
478 
479 	@Override
480 	public Permission createPermission(Permission permission)
481 			throws RiceIllegalArgumentException, RiceIllegalStateException {
482         incomingParamCheck(permission, "permission");
483 
484         if (StringUtils.isNotBlank(permission.getId()) && getPermission(permission.getId()) != null) {
485             throw new RiceIllegalStateException("the permission to create already exists: " + permission);
486         }
487         List<PermissionAttributeBo> attrBos = Collections.emptyList();
488         if (permission.getTemplate() != null) {
489             attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId());
490         }
491         PermissionBo bo = PermissionBo.from(permission);
492         if (bo.getTemplate() == null && bo.getTemplateId() != null) {
493             bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId())));
494         }
495         bo.setAttributeDetails(attrBos);
496         return PermissionBo.to(businessObjectService.save(bo));
497 	}
498 
499 	@Override
500 	public Permission updatePermission(Permission permission)
501 			throws RiceIllegalArgumentException, RiceIllegalStateException {
502         incomingParamCheck(permission, "permission");
503 
504         PermissionBo oldPermission = getPermissionImpl(permission.getId());
505         if (StringUtils.isBlank(permission.getId()) || oldPermission == null) {
506             throw new RiceIllegalStateException("the permission does not exist: " + permission);
507         }
508 
509         //List<PermissionAttributeBo> attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId());
510 
511         List<PermissionAttributeBo> oldAttrBos = oldPermission.getAttributeDetails();
512         //put old attributes in map for easier updating
513         Map<String, PermissionAttributeBo> oldAttrMap = new HashMap<String, PermissionAttributeBo>();
514         for (PermissionAttributeBo oldAttr : oldAttrBos) {
515             oldAttrMap.put(oldAttr.getKimAttribute().getAttributeName(), oldAttr);
516         }
517         List<PermissionAttributeBo> newAttrBos = new ArrayList<PermissionAttributeBo>();
518         for (String key : permission.getAttributes().keySet()) {
519             if (oldAttrMap.containsKey(key)) {
520                 PermissionAttributeBo updatedAttr = oldAttrMap.get(key);
521                 updatedAttr.setAttributeValue(permission.getAttributes().get(key));
522                 newAttrBos.add(updatedAttr);
523             } else { //new attribute
524                 newAttrBos.addAll(KimAttributeDataBo.createFrom(PermissionAttributeBo.class, Collections.singletonMap(key, permission.getAttributes().get(key)), permission.getTemplate().getKimTypeId()));
525             }
526         }
527         PermissionBo bo = PermissionBo.from(permission);
528         if (CollectionUtils.isNotEmpty(newAttrBos)) {
529             bo.getAttributeDetails().clear();
530             bo.setAttributeDetails(newAttrBos);
531         }
532         if (bo.getTemplate() == null && bo.getTemplateId() != null) {
533             bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId())));
534         }
535 
536         return PermissionBo.to(businessObjectService.save(bo));		
537 	}
538 	
539     @Override
540     public Permission findPermByNamespaceCodeAndName(String namespaceCode, String permissionName)
541             throws RiceIllegalArgumentException {
542         incomingParamCheck(namespaceCode, "namespaceCode");
543         incomingParamCheck(permissionName, "permissionName");
544 
545         PermissionBo permissionBo = getPermissionBoByName(namespaceCode, permissionName);
546         if (permissionBo != null) {
547             return PermissionBo.to(permissionBo);
548         }
549         return null;
550     }
551     
552     protected PermissionBo getPermissionBoByName(String namespaceCode, String permissionName) {
553         if (StringUtils.isBlank(namespaceCode)
554                 || StringUtils.isBlank(permissionName)) {
555             return null;
556         }
557         Map<String, String> criteria = new HashMap<String, String>();
558         criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode);
559         criteria.put(KimConstants.UniqueKeyConstants.NAME, permissionName);
560         criteria.put(KRADPropertyConstants.ACTIVE, "Y");
561         // while this is not actually the primary key - there will be at most one row with these criteria
562         return businessObjectService.findByPrimaryKey(PermissionBo.class, criteria);
563     }
564 
565     @Override
566     public PermissionQueryResults findPermissions(final QueryByCriteria queryByCriteria)
567             throws RiceIllegalArgumentException {
568         incomingParamCheck(queryByCriteria, "queryByCriteria");
569 
570         LookupCustomizer.Builder<PermissionBo> lc = LookupCustomizer.Builder.create();
571         lc.setPredicateTransform(AttributeTransform.getInstance());
572 
573         GenericQueryResults<PermissionBo> results = criteriaLookupService.lookup(PermissionBo.class, queryByCriteria, lc.build());
574 
575         PermissionQueryResults.Builder builder = PermissionQueryResults.Builder.create();
576         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
577         builder.setTotalRowCount(results.getTotalRowCount());
578 
579         final List<Permission.Builder> ims = new ArrayList<Permission.Builder>();
580         for (PermissionBo bo : results.getResults()) {
581             ims.add(Permission.Builder.create(bo));
582         }
583 
584         builder.setResults(ims);
585         return builder.build();
586     }
587 
588     @Override
589     public TemplateQueryResults findPermissionTemplates(final QueryByCriteria queryByCriteria)
590             throws RiceIllegalArgumentException {
591         incomingParamCheck(queryByCriteria, "queryByCriteria");
592 
593         GenericQueryResults<PermissionTemplateBo> results = criteriaLookupService.lookup(PermissionTemplateBo.class, queryByCriteria);
594 
595         TemplateQueryResults.Builder builder = TemplateQueryResults.Builder.create();
596         builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
597         builder.setTotalRowCount(results.getTotalRowCount());
598 
599         final List<Template.Builder> ims = new ArrayList<Template.Builder>();
600         for (PermissionTemplateBo bo : results.getResults()) {
601             ims.add(Template.Builder.create(bo));
602         }
603 
604         builder.setResults(ims);
605         return builder.build();
606     }
607 
608     private List<String> getRoleIdsForPermissions( Collection<Permission> permissions ) {
609         if (CollectionUtils.isEmpty(permissions)) {
610             return Collections.emptyList();
611         }
612         List<String> ids = new ArrayList<String>();
613         for (Permission p : permissions) {
614             ids.add(p.getId());
615         }
616 
617         QueryByCriteria query = QueryByCriteria.Builder.fromPredicates(equal("active", "true"), in("permissionId", ids.toArray(new String[]{})));
618 
619         GenericQueryResults<RolePermissionBo> results = criteriaLookupService.lookup(RolePermissionBo.class, query);
620         List<String> roleIds = new ArrayList<String>();
621         for (RolePermissionBo bo : results.getResults()) {
622             roleIds.add(bo.getRoleId());
623         }
624         return Collections.unmodifiableList(roleIds);
625     }
626 	
627 	/**
628      * Sets the kimTypeInfoService attribute value.
629      *
630      * @param kimTypeInfoService The kimTypeInfoService to set.
631      */
632 	public void setKimTypeInfoService(KimTypeInfoService kimTypeInfoService) {
633 		this.kimTypeInfoService = kimTypeInfoService;
634 	}
635 	
636 	/**
637      * Sets the defaultPermissionTypeService attribute value.
638      *
639      * @param defaultPermissionTypeService The defaultPermissionTypeService to set.
640      */
641 	public void setDefaultPermissionTypeService(PermissionTypeService defaultPermissionTypeService) {
642     	this.defaultPermissionTypeService = defaultPermissionTypeService;
643 	}
644 	
645 	/**
646      * Sets the roleService attribute value.
647      *
648      * @param roleService The roleService to set.
649      */
650 	public void setRoleService(RoleService roleService) {
651 		this.roleService = roleService;
652 	}
653 
654     /**
655      * Sets the businessObjectService attribute value.
656      *
657      * @param businessObjectService The businessObjectService to set.
658      */
659     public void setBusinessObjectService(final BusinessObjectService businessObjectService) {
660         this.businessObjectService = businessObjectService;
661     }
662 
663     /**
664      * Sets the criteriaLookupService attribute value.
665      *
666      * @param criteriaLookupService The criteriaLookupService to set.
667      */
668     public void setCriteriaLookupService(final CriteriaLookupService criteriaLookupService) {
669         this.criteriaLookupService = criteriaLookupService;
670     }
671 
672     private void incomingParamCheck(Object object, String name) {
673         if (object == null) {
674             throw new RiceIllegalArgumentException(name + " was null");
675         } else if (object instanceof String
676                 && StringUtils.isBlank((String) object)) {
677             throw new RiceIllegalArgumentException(name + " was blank");
678         }
679     }
680 }