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.impl.responsibility; 017 018import org.apache.commons.beanutils.PropertyUtils; 019import org.apache.commons.lang.StringUtils; 020import org.apache.log4j.Logger; 021import org.kuali.rice.core.api.membership.MemberType; 022import org.kuali.rice.kew.api.KewApiConstants; 023import org.kuali.rice.kim.api.KimConstants; 024import org.kuali.rice.kim.api.responsibility.ResponsibilityContract; 025import org.kuali.rice.kim.api.services.KimApiServiceLocator; 026import org.kuali.rice.kim.impl.role.RoleBo; 027import org.kuali.rice.kim.impl.role.RoleResponsibilityBo; 028import org.kuali.rice.kim.lookup.RoleMemberLookupableHelperServiceImpl; 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 ResponsibilityLookupableHelperServiceImpl extends RoleMemberLookupableHelperServiceImpl { 046 047 private static final Logger LOG = Logger.getLogger( ResponsibilityLookupableHelperServiceImpl.class ); 048 049 private static final long serialVersionUID = -2882500971924192124L; 050 051 private static LookupService lookupService; 052 053 private static boolean reviewResponsibilityDocumentTypeNameLoaded = false; 054 private static String reviewResponsibilityDocumentTypeName = null; 055 056 @SuppressWarnings("unchecked") 057 @Override 058 public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) { 059 List<HtmlData> htmlDataList = new ArrayList<HtmlData>(); 060 // convert the UberResponsibilityBo class into a ReviewResponsibility object 061 if ( (((UberResponsibilityBo)businessObject).getTemplate() != null) 062 && ((UberResponsibilityBo)businessObject).getTemplate().getName().equals( KewApiConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME ) ) { 063 ReviewResponsibilityBo reviewResp = new ReviewResponsibilityBo( (ResponsibilityContract)businessObject ); 064 businessObject = reviewResp; 065 if (allowsMaintenanceEditAction(businessObject)) { 066 htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames)); 067 } 068 if (allowsMaintenanceNewOrCopyAction()) { 069 htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames)); 070 } 071 } 072 return htmlDataList; 073 } 074 075 @SuppressWarnings("unchecked") 076 protected String getActionUrlHref(BusinessObject businessObject, String methodToCall, List pkNames){ 077 Properties parameters = new Properties(); 078 parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, methodToCall); 079 // TODO: why is this not using the businessObject parmeter's class? 080 parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObject.getClass().getName()); 081 parameters.put(KRADConstants.OVERRIDE_KEYS, KimConstants.PrimaryKeyConstants.RESPONSIBILITY_ID); 082 parameters.put(KRADConstants.COPY_KEYS, KimConstants.PrimaryKeyConstants.RESPONSIBILITY_ID); 083 if (StringUtils.isNotBlank(getReturnLocation())) { 084 parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation()); 085 } 086 parameters.putAll(getParametersFromPrimaryKey(businessObject, pkNames)); 087 return UrlFactory.parameterizeUrl(KRADConstants.MAINTENANCE_ACTION, parameters); 088 } 089 090 @Override 091 protected String getMaintenanceDocumentTypeName() { 092 if ( !reviewResponsibilityDocumentTypeNameLoaded ) { 093 reviewResponsibilityDocumentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(ReviewResponsibilityBo.class); 094 reviewResponsibilityDocumentTypeNameLoaded = true; 095 } 096 return reviewResponsibilityDocumentTypeName; 097 } 098 099 @Override 100 protected List<? extends BusinessObject> getMemberSearchResults(Map<String, String> searchCriteria, boolean unbounded) { 101 Map<String, String> responsibilitySearchCriteria = buildSearchCriteria(searchCriteria); 102 Map<String, String> roleSearchCriteria = buildRoleSearchCriteria(searchCriteria); 103 boolean responsibilityCriteriaEmpty = responsibilitySearchCriteria==null || responsibilitySearchCriteria.isEmpty(); 104 boolean roleCriteriaEmpty = roleSearchCriteria==null || roleSearchCriteria.isEmpty(); 105 106 List<UberResponsibilityBo> responsibilitySearchResultsCopy = new CollectionIncomplete<UberResponsibilityBo>(new ArrayList<UberResponsibilityBo>(), new Long(0)); 107 if(!responsibilityCriteriaEmpty && !roleCriteriaEmpty){ 108 responsibilitySearchResultsCopy = getCombinedSearchResults(responsibilitySearchCriteria, roleSearchCriteria, unbounded); 109 } else if(responsibilityCriteriaEmpty && !roleCriteriaEmpty){ 110 responsibilitySearchResultsCopy = getResponsibilitiesWithRoleSearchCriteria(roleSearchCriteria, unbounded); 111 } else if(!responsibilityCriteriaEmpty && roleCriteriaEmpty){ 112 responsibilitySearchResultsCopy = getResponsibilitiesWithResponsibilitySearchCriteria(responsibilitySearchCriteria, unbounded); 113 } else if(responsibilityCriteriaEmpty && roleCriteriaEmpty){ 114 return getAllResponsibilities(unbounded); 115 } 116 return responsibilitySearchResultsCopy; 117 } 118 119 private List<UberResponsibilityBo> getAllResponsibilities(boolean unbounded){ 120 List<UberResponsibilityBo> responsibilities = searchResponsibilities(new HashMap<String, String>(), unbounded); 121 for(UberResponsibilityBo responsibility: responsibilities) { 122 populateAssignedToRoles(responsibility); 123 } 124 return responsibilities; 125 } 126 127 private List<UberResponsibilityBo> getCombinedSearchResults( 128 Map<String, String> responsibilitySearchCriteria, Map<String, String> roleSearchCriteria, boolean unbounded){ 129 List<UberResponsibilityBo> responsibilitySearchResults = searchResponsibilities(responsibilitySearchCriteria, unbounded); 130 List<RoleBo> roleSearchResults = searchRoles(roleSearchCriteria, unbounded); 131 List<UberResponsibilityBo> responsibilitiesForRoleSearchResults = getResponsibilitiesForRoleSearchResults(roleSearchResults, unbounded); 132 List<UberResponsibilityBo> matchedResponsibilities = new CollectionIncomplete<UberResponsibilityBo>( 133 new ArrayList<UberResponsibilityBo>(), getActualSizeIfTruncated(responsibilitiesForRoleSearchResults)); 134 if((responsibilitySearchResults!=null && !responsibilitySearchResults.isEmpty()) && 135 (responsibilitiesForRoleSearchResults!=null && !responsibilitiesForRoleSearchResults.isEmpty())){ 136 for(UberResponsibilityBo responsibility: responsibilitySearchResults){ 137 for(UberResponsibilityBo responsibilityFromRoleSearch: responsibilitiesForRoleSearchResults){ 138 if(responsibilityFromRoleSearch.getId().equals(responsibility.getId())) { 139 matchedResponsibilities.add(responsibilityFromRoleSearch); 140 } 141 } 142 } 143 } 144 145 return matchedResponsibilities; 146 } 147 148 @SuppressWarnings("unchecked") 149 private List<UberResponsibilityBo> searchResponsibilities(Map<String, String> responsibilitySearchCriteria, boolean unbounded){ 150 return getResponsibilitiesSearchResultsCopy((List<ResponsibilityBo>) 151 getLookupService().findCollectionBySearchHelper( 152 ResponsibilityBo.class, responsibilitySearchCriteria, unbounded)); 153 } 154 155 private List<UberResponsibilityBo> getResponsibilitiesWithRoleSearchCriteria(Map<String, String> roleSearchCriteria, boolean unbounded){ 156 List<RoleBo> roleSearchResults = searchRoles(roleSearchCriteria, unbounded); 157 return getResponsibilitiesForRoleSearchResults(roleSearchResults, unbounded); 158 } 159 160 private List<UberResponsibilityBo> getResponsibilitiesForRoleSearchResults(List<RoleBo> roleSearchResults, boolean unbounded){ 161 Long actualSizeIfTruncated = getActualSizeIfTruncated(roleSearchResults); 162 List<UberResponsibilityBo> responsibilities = new ArrayList<UberResponsibilityBo>(); 163 List<UberResponsibilityBo> tempResponsibilities; 164 List<String> collectedResponsibilityIds = new ArrayList<String>(); 165 Map<String, String> responsibilityCriteria; 166 167 for(RoleBo roleImpl: roleSearchResults){ 168 responsibilityCriteria = new HashMap<String, String>(); 169 responsibilityCriteria.put("roleResponsibilities.roleId", roleImpl.getId()); 170 tempResponsibilities = searchResponsibilities(responsibilityCriteria, unbounded); 171 actualSizeIfTruncated += getActualSizeIfTruncated(tempResponsibilities); 172 for(UberResponsibilityBo responsibility: tempResponsibilities){ 173 if(!collectedResponsibilityIds.contains(responsibility.getId())){ 174 populateAssignedToRoles(responsibility); 175 collectedResponsibilityIds.add(responsibility.getId()); 176 responsibilities.add(responsibility); 177 } 178 //need to find roles that current role is a member of and build search string 179 List<String> parentRoleIds = KimApiServiceLocator.getRoleService().getMemberParentRoleIds(MemberType.ROLE.getCode(), roleImpl.getId()); 180 for (String parentRoleId : parentRoleIds) { 181 Map<String, String> roleSearchCriteria = new HashMap<String, String>(); 182 roleSearchCriteria.put("id", parentRoleId); 183 //get all parent role permissions and merge them with current permissions 184 responsibilities = mergeResponsibilityLists(responsibilities, getResponsibilitiesWithRoleSearchCriteria(roleSearchCriteria, unbounded)); 185 } 186 } 187 } 188 return new CollectionIncomplete<UberResponsibilityBo>(responsibilities, actualSizeIfTruncated); 189 } 190 191 private void populateAssignedToRoles(UberResponsibilityBo responsibility){ 192 if ( responsibility.getAssignedToRoles().isEmpty() ) { 193 for(RoleResponsibilityBo roleResponsibility: responsibility.getRoleResponsibilities()){ 194 responsibility.getAssignedToRoles().add(KradDataServiceLocator.getDataObjectService().find(RoleBo.class, 195 roleResponsibility.getRoleId())); 196 } 197 } 198 } 199 200 private List<UberResponsibilityBo> getResponsibilitiesWithResponsibilitySearchCriteria(Map<String, String> responsibilitySearchCriteria, boolean unbounded){ 201 String detailCriteriaStr = responsibilitySearchCriteria.remove( DETAIL_CRITERIA ); 202 Map<String, String> detailCriteria = parseDetailCriteria(detailCriteriaStr); 203 final List<UberResponsibilityBo> responsibilities = searchResponsibilities(responsibilitySearchCriteria, unbounded); 204 List<UberResponsibilityBo> filteredResponsibilities = new CollectionIncomplete<UberResponsibilityBo>( 205 new ArrayList<UberResponsibilityBo>(), getActualSizeIfTruncated(responsibilities)); 206 for(UberResponsibilityBo responsibility: responsibilities){ 207 if ( detailCriteria.isEmpty() ) { 208 filteredResponsibilities.add(responsibility); 209 populateAssignedToRoles(responsibility); 210 } else { 211 if ( isMapSubset( new HashMap<String, String>(responsibility.getAttributes()), detailCriteria ) ) { 212 filteredResponsibilities.add(responsibility); 213 populateAssignedToRoles(responsibility); 214 } 215 } 216 } 217 return filteredResponsibilities; 218 } 219 220 private List<UberResponsibilityBo> getResponsibilitiesSearchResultsCopy(List<ResponsibilityBo> responsibilitySearchResults){ 221 List<UberResponsibilityBo> responsibilitySearchResultsCopy = new CollectionIncomplete<UberResponsibilityBo>( 222 new ArrayList<UberResponsibilityBo>(), getActualSizeIfTruncated(responsibilitySearchResults)); 223 for(ResponsibilityBo responsibilityImpl: responsibilitySearchResults){ 224 UberResponsibilityBo responsibilityCopy = new UberResponsibilityBo(); 225 226 try { 227 PropertyUtils.copyProperties(responsibilityCopy, responsibilityImpl); 228 //Hack for tomcat 7 KULRICE:5927 229 responsibilityCopy.setTemplate(responsibilityImpl.getTemplate()); 230 } catch (IllegalAccessException e) { 231 throw new RuntimeException("unable to copy properties"); 232 } catch (InvocationTargetException e) { 233 throw new RuntimeException("unable to copy properties"); 234 } catch (NoSuchMethodException e) { 235 throw new RuntimeException("unable to copy properties"); 236 } 237 238 responsibilitySearchResultsCopy.add(responsibilityCopy); 239 } 240 return responsibilitySearchResultsCopy; 241 } 242 243 244 /** 245 * @return the lookupService 246 */ 247 public LookupService getLookupService() { 248 if ( lookupService == null ) { 249 lookupService = KRADServiceLocatorWeb.getLookupService(); 250 } 251 return lookupService; 252 } 253 254 private List<UberResponsibilityBo> mergeResponsibilityLists(List<UberResponsibilityBo> perm1, List<UberResponsibilityBo> perm2) { 255 List<UberResponsibilityBo> returnList = new ArrayList<UberResponsibilityBo>(perm1); 256 List<String> responsibilityIds = new ArrayList<String>(perm1.size()); 257 for (UberResponsibilityBo perm : returnList) { 258 responsibilityIds.add(perm.getId()); 259 } 260 for (int i=0; i<perm2.size(); i++) { 261 if (!responsibilityIds.contains(perm2.get(i).getId())) { 262 returnList.add(perm2.get(i)); 263 } 264 } 265 return returnList; 266 } 267}