001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kim.lookup; 017 018import org.apache.commons.beanutils.PropertyUtils; 019import org.apache.commons.lang.StringUtils; 020import org.kuali.rice.core.api.membership.MemberType; 021import org.kuali.rice.kim.api.KimConstants; 022import org.kuali.rice.kim.api.role.RoleService; 023import org.kuali.rice.kim.api.services.KimApiServiceLocator; 024import org.kuali.rice.kim.impl.permission.GenericPermissionBo; 025import org.kuali.rice.kim.impl.permission.PermissionBo; 026import org.kuali.rice.kim.impl.permission.UberPermissionBo; 027import org.kuali.rice.kim.impl.role.RoleBo; 028import org.kuali.rice.kim.impl.role.RolePermissionBo; 029import org.kuali.rice.kns.lookup.HtmlData; 030import org.kuali.rice.krad.bo.BusinessObject; 031import org.kuali.rice.krad.lookup.CollectionIncomplete; 032import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 033import org.kuali.rice.krad.service.LookupService; 034import org.kuali.rice.krad.util.KRADConstants; 035import org.kuali.rice.krad.util.UrlFactory; 036 037import java.lang.reflect.InvocationTargetException; 038import java.util.ArrayList; 039import java.util.HashMap; 040import java.util.List; 041import java.util.Map; 042import java.util.Properties; 043 044public class PermissionLookupableHelperServiceImpl extends RoleMemberLookupableHelperServiceImpl { 045 046 private static final long serialVersionUID = -3578448525862270477L; 047 048 private transient LookupService lookupService; 049 private transient RoleService roleService; 050 private volatile String genericPermissionDocumentTypeName; 051 052 @Override 053 public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) { 054 List<HtmlData> htmlDataList = new ArrayList<HtmlData>(); 055 // convert the PermissionBo class into an UberPermission object 056 businessObject = new GenericPermissionBo((UberPermissionBo)businessObject); 057 if (allowsMaintenanceEditAction(businessObject)) { 058 htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames)); 059 } 060 if (allowsMaintenanceNewOrCopyAction()) { 061 htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames)); 062 } 063 return htmlDataList; 064 } 065 066 protected String getActionUrlHref(BusinessObject businessObject, String methodToCall, List pkNames){ 067 Properties parameters = new Properties(); 068 parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, methodToCall); 069 parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObject.getClass().getName()); 070 parameters.put(KRADConstants.OVERRIDE_KEYS, KimConstants.PrimaryKeyConstants.PERMISSION_ID); 071 parameters.put(KRADConstants.COPY_KEYS, KimConstants.PrimaryKeyConstants.PERMISSION_ID); 072 if (StringUtils.isNotBlank(getReturnLocation())) { 073 parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation()); 074 } 075 parameters.putAll(getParametersFromPrimaryKey(businessObject, pkNames)); 076 return UrlFactory.parameterizeUrl(KRADConstants.MAINTENANCE_ACTION, parameters); 077 } 078 079 @Override 080 protected String getMaintenanceDocumentTypeName() { 081 //using DCL idiom to cache genericPermissionDocumentTypeName. 082 //see effective java 2nd ed. pg. 71 083 String g = genericPermissionDocumentTypeName; 084 if (g == null) { 085 synchronized (this) { 086 g = genericPermissionDocumentTypeName; 087 if (g == null) { 088 genericPermissionDocumentTypeName = g = getMaintenanceDocumentDictionaryService().getDocumentTypeName( 089 GenericPermissionBo.class); 090 } 091 } 092 } 093 094 return g; 095 } 096 097 @Override 098 protected List<? extends BusinessObject> getMemberSearchResults(Map<String, String> searchCriteria, boolean unbounded) { 099 Map<String, String> permissionSearchCriteria = buildSearchCriteria(searchCriteria); 100 Map<String, String> roleSearchCriteria = buildRoleSearchCriteria(searchCriteria); 101 boolean permissionCriteriaEmpty = permissionSearchCriteria==null || permissionSearchCriteria.isEmpty(); 102 boolean roleCriteriaEmpty = roleSearchCriteria==null || roleSearchCriteria.isEmpty(); 103 104 List<UberPermissionBo> permissionSearchResultsCopy = new CollectionIncomplete<UberPermissionBo>(new ArrayList<UberPermissionBo>(), new Long(0)); 105 if(!permissionCriteriaEmpty && !roleCriteriaEmpty){ 106 permissionSearchResultsCopy = getCombinedSearchResults(permissionSearchCriteria, roleSearchCriteria, unbounded); 107 } else if(permissionCriteriaEmpty && !roleCriteriaEmpty){ 108 permissionSearchResultsCopy = getPermissionsWithRoleSearchCriteria(roleSearchCriteria, unbounded); 109 } else if(!permissionCriteriaEmpty && roleCriteriaEmpty){ 110 permissionSearchResultsCopy = getPermissionsWithPermissionSearchCriteria(permissionSearchCriteria, unbounded); 111 } else if(permissionCriteriaEmpty && roleCriteriaEmpty){ 112 return getAllPermissions(unbounded); 113 } 114 return permissionSearchResultsCopy; 115 } 116 117 private List<UberPermissionBo> getAllPermissions(boolean unbounded){ 118 List<UberPermissionBo> permissions = searchPermissions(new HashMap<String, String>(), unbounded); 119 for(UberPermissionBo permission: permissions) { 120 populateAssignedToRoles(permission); 121 } 122 return permissions; 123 } 124 125 private List<UberPermissionBo> getCombinedSearchResults( 126 Map<String, String> permissionSearchCriteria, Map<String, String> roleSearchCriteria, boolean unbounded){ 127 List<UberPermissionBo> permissionSearchResults = searchPermissions(permissionSearchCriteria, unbounded); 128 List<RoleBo> roleSearchResults = searchRoles(roleSearchCriteria, unbounded); 129 List<UberPermissionBo> permissionsForRoleSearchResults = getPermissionsForRoleSearchResults(roleSearchResults, unbounded); 130 List<UberPermissionBo> matchedPermissions = new CollectionIncomplete<UberPermissionBo>( 131 new ArrayList<UberPermissionBo>(), getActualSizeIfTruncated(permissionsForRoleSearchResults)); 132 if((permissionSearchResults!=null && !permissionSearchResults.isEmpty()) && 133 (permissionsForRoleSearchResults!=null && !permissionsForRoleSearchResults.isEmpty())){ 134 for(UberPermissionBo permission: permissionSearchResults){ 135 for(UberPermissionBo permissionFromRoleSearch: permissionsForRoleSearchResults){ 136 if(permissionFromRoleSearch.getId().equals(permission.getId())) { 137 matchedPermissions.add(permissionFromRoleSearch); 138 } 139 } 140 } 141 } 142 return matchedPermissions; 143 } 144 145 private List<UberPermissionBo> searchPermissions(Map<String, String> permissionSearchCriteria, boolean unbounded){ 146 return getPermissionsSearchResultsCopy(new ArrayList<PermissionBo>(getLookupService().findCollectionBySearchHelper( 147 PermissionBo.class, permissionSearchCriteria, unbounded))); 148 149 } 150 151 private List<UberPermissionBo> getPermissionsWithRoleSearchCriteria(Map<String, String> roleSearchCriteria, boolean unbounded){ 152 return getPermissionsForRoleSearchResults(searchRoles(roleSearchCriteria, unbounded), unbounded); 153 } 154 155 private List<UberPermissionBo> getPermissionsForRoleSearchResults(List<RoleBo> roleSearchResults, boolean unbounded){ 156 Long actualSizeIfTruncated = getActualSizeIfTruncated(roleSearchResults); 157 List<UberPermissionBo> permissions = new ArrayList<UberPermissionBo>(); 158 List<UberPermissionBo> tempPermissions; 159 List<String> collectedPermissionIds = new ArrayList<String>(); 160 Map<String, String> permissionCriteria; 161 162 for(RoleBo roleImpl: roleSearchResults){ 163 permissionCriteria = new HashMap<String, String>(); 164 permissionCriteria.put("rolePermissions.roleId", roleImpl.getId()); 165 tempPermissions = searchPermissions(permissionCriteria, unbounded); 166 actualSizeIfTruncated += getActualSizeIfTruncated(tempPermissions); 167 for(UberPermissionBo permission: tempPermissions){ 168 if(!collectedPermissionIds.contains(permission.getId())){ 169 populateAssignedToRoles(permission); 170 collectedPermissionIds.add(permission.getId()); 171 permissions.add(permission); 172 } 173 } 174 //need to find roles that current role is a member of and build search string 175 List<String> parentRoleIds = KimApiServiceLocator.getRoleService().getMemberParentRoleIds(MemberType.ROLE.getCode(), roleImpl.getId()); 176 for (String parentRoleId : parentRoleIds) { 177 Map<String, String> roleSearchCriteria = new HashMap<String, String>(); 178 roleSearchCriteria.put("roleId", parentRoleId); 179 //get all parent role permissions and merge them with current permissions 180 permissions = mergePermissionLists(permissions, getPermissionsWithRoleSearchCriteria(roleSearchCriteria, unbounded)); 181 } 182 } 183 184 return new CollectionIncomplete<UberPermissionBo>(permissions, actualSizeIfTruncated); 185 } 186 187 188 private void populateAssignedToRoles(UberPermissionBo permission){ 189 Map<String, String> criteria; 190 for(RolePermissionBo rolePermission: permission.getRolePermissions()){ 191 if ( rolePermission.isActive() ) { 192 criteria = new HashMap<String, String>(); 193 criteria.put("id", rolePermission.getRoleId()); 194 // permission.getAssignedToRoles().add((RoleBo)getBusinessObjectService().findByPrimaryKey(RoleBo.class, criteria)); 195 RoleBo roleBo = getBusinessObjectService().findByPrimaryKey(RoleBo.class, criteria); 196 permission.getAssignedToRoles().add(roleBo); 197 198 } 199 } 200 } 201 202 private List<UberPermissionBo> getPermissionsWithPermissionSearchCriteria( 203 Map<String, String> permissionSearchCriteria, boolean unbounded){ 204 String detailCriteriaStr = permissionSearchCriteria.remove( DETAIL_CRITERIA ); 205 Map<String, String> detailCriteria = parseDetailCriteria(detailCriteriaStr); 206 207 final List<UberPermissionBo> permissions = searchPermissions(permissionSearchCriteria, unbounded); 208 List<UberPermissionBo> filteredPermissions = new CollectionIncomplete<UberPermissionBo>( 209 new ArrayList<UberPermissionBo>(), getActualSizeIfTruncated(permissions)); 210 for(UberPermissionBo perm: permissions){ 211 if ( detailCriteria.isEmpty() ) { 212 filteredPermissions.add(perm); 213 populateAssignedToRoles(perm); 214 } else { 215 if ( isMapSubset( new HashMap<String, String>(perm.getDetails()), detailCriteria ) ) { 216 filteredPermissions.add(perm); 217 populateAssignedToRoles(perm); 218 } 219 } 220 } 221 return filteredPermissions; 222 } 223 224 private List<UberPermissionBo> getPermissionsSearchResultsCopy(List<PermissionBo> permissionSearchResults){ 225 List<UberPermissionBo> permissionSearchResultsCopy = new CollectionIncomplete<UberPermissionBo>( 226 new ArrayList<UberPermissionBo>(), getActualSizeIfTruncated(permissionSearchResults)); 227 for(PermissionBo permissionBo: permissionSearchResults){ 228 UberPermissionBo permissionCopy = new UberPermissionBo(); 229 230 try { 231 PropertyUtils.copyProperties(permissionCopy, permissionBo); 232 //Hack for tomcat 7 KULRICE-5927 233 permissionCopy.setTemplate(permissionBo.getTemplate()); 234 } catch (IllegalAccessException e) { 235 throw new RuntimeException("unable to copy properties"); 236 } catch (InvocationTargetException e) { 237 throw new RuntimeException("unable to copy properties"); 238 } catch (NoSuchMethodException e) { 239 throw new RuntimeException("unable to copy properties"); 240 } 241 242 permissionSearchResultsCopy.add(permissionCopy); 243 } 244 return permissionSearchResultsCopy; 245 } 246 247 /** 248 * @return the lookupService 249 */ 250 public synchronized LookupService getLookupService() { 251 if ( lookupService == null ) { 252 lookupService = KRADServiceLocatorWeb.getLookupService(); 253 } 254 return lookupService; 255 } 256 257 public synchronized RoleService getRoleService() { 258 if (roleService == null) { 259 roleService = KimApiServiceLocator.getRoleService(); 260 } 261 return roleService; 262 } 263 264 private List<UberPermissionBo> mergePermissionLists(List<UberPermissionBo> perm1, List<UberPermissionBo> perm2) { 265 List<UberPermissionBo> returnList = new ArrayList<UberPermissionBo>(perm1); 266 List<String> permissionIds = new ArrayList<String>(perm1.size()); 267 for (UberPermissionBo perm : returnList) { 268 permissionIds.add(perm.getId()); 269 } 270 for (int i=0; i<perm2.size(); i++) { 271 if (!permissionIds.contains(perm2.get(i).getId())) { 272 returnList.add(perm2.get(i)); 273 } 274 } 275 return returnList; 276 } 277}