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