View Javadoc
1   /**
2    * Copyright 2005-2015 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.responsibility;
17  
18  import org.apache.commons.beanutils.PropertyUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.kuali.rice.core.api.membership.MemberType;
22  import org.kuali.rice.kew.api.KewApiConstants;
23  import org.kuali.rice.kim.api.KimConstants;
24  import org.kuali.rice.kim.api.responsibility.ResponsibilityContract;
25  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
26  import org.kuali.rice.kim.impl.role.RoleBo;
27  import org.kuali.rice.kim.impl.role.RoleResponsibilityBo;
28  import org.kuali.rice.kim.lookup.RoleMemberLookupableHelperServiceImpl;
29  import org.kuali.rice.kns.lookup.HtmlData;
30  import org.kuali.rice.krad.bo.BusinessObject;
31  import org.kuali.rice.krad.data.KradDataServiceLocator;
32  import org.kuali.rice.krad.lookup.CollectionIncomplete;
33  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
34  import org.kuali.rice.krad.service.LookupService;
35  import org.kuali.rice.krad.util.KRADConstants;
36  import org.kuali.rice.krad.util.UrlFactory;
37  
38  import java.lang.reflect.InvocationTargetException;
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Properties;
44  
45  public class ResponsibilityLookupableHelperServiceImpl extends RoleMemberLookupableHelperServiceImpl {
46  
47  	private static final Logger LOG = Logger.getLogger( ResponsibilityLookupableHelperServiceImpl.class );
48  	
49  	private static final long serialVersionUID = -2882500971924192124L;
50  	
51  	private static LookupService lookupService;
52  
53  	private static boolean reviewResponsibilityDocumentTypeNameLoaded = false;
54  	private static String reviewResponsibilityDocumentTypeName = null;
55  	
56  	@SuppressWarnings("unchecked")
57  	@Override
58  	public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) {
59      	List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
60      	// convert the UberResponsibilityBo class into a ReviewResponsibility object
61          if ( (((UberResponsibilityBo)businessObject).getTemplate() != null)
62                  && ((UberResponsibilityBo)businessObject).getTemplate().getName().equals( KewApiConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME ) ) {
63          	ReviewResponsibilityBo reviewResp = new ReviewResponsibilityBo( (ResponsibilityContract)businessObject );
64          	businessObject = reviewResp;
65  	        if (allowsMaintenanceEditAction(businessObject)) {
66  	        	htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames));
67  	        }
68  	        if (allowsMaintenanceNewOrCopyAction()) {
69  	        	htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames));
70  	        }
71          }
72          return htmlDataList;
73  	}
74  
75      @SuppressWarnings("unchecked")
76  	protected String getActionUrlHref(BusinessObject businessObject, String methodToCall, List pkNames){
77          Properties parameters = new Properties();
78          parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, methodToCall);
79          // TODO: why is this not using the businessObject parmeter's class?
80          parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObject.getClass().getName());
81          parameters.put(KRADConstants.OVERRIDE_KEYS, KimConstants.PrimaryKeyConstants.RESPONSIBILITY_ID);
82          parameters.put(KRADConstants.COPY_KEYS, KimConstants.PrimaryKeyConstants.RESPONSIBILITY_ID);
83          if (StringUtils.isNotBlank(getReturnLocation())) {
84          	parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation());
85  		}
86          parameters.putAll(getParametersFromPrimaryKey(businessObject, pkNames));
87          return UrlFactory.parameterizeUrl(KRADConstants.MAINTENANCE_ACTION, parameters);
88      }
89  	
90  	@Override
91  	protected String getMaintenanceDocumentTypeName() {
92  		if ( !reviewResponsibilityDocumentTypeNameLoaded ) {
93  			reviewResponsibilityDocumentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(ReviewResponsibilityBo.class);
94  			reviewResponsibilityDocumentTypeNameLoaded = true;
95  		}
96  		return reviewResponsibilityDocumentTypeName;
97  	}
98  	
99  	@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 }