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}