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