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.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.services.KimApiServiceLocator;
025import org.kuali.rice.kim.impl.role.RoleBo;
026import org.kuali.rice.kim.impl.role.RoleResponsibilityBo;
027import org.kuali.rice.kim.lookup.RoleMemberLookupableHelperServiceImpl;
028import org.kuali.rice.kns.lookup.HtmlData;
029import org.kuali.rice.krad.bo.BusinessObject;
030import org.kuali.rice.krad.lookup.CollectionIncomplete;
031import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
032import org.kuali.rice.krad.service.LookupService;
033import org.kuali.rice.krad.util.KRADConstants;
034import org.kuali.rice.krad.util.UrlFactory;
035
036import java.lang.reflect.InvocationTargetException;
037import java.util.ArrayList;
038import java.util.HashMap;
039import java.util.List;
040import java.util.Map;
041import java.util.Properties;
042
043public 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}