001/**
002 * Copyright 2005-2018 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.kns.web.struts.action;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.struts.action.ActionForm;
020import org.apache.struts.action.ActionForward;
021import org.apache.struts.action.ActionMapping;
022import org.kuali.rice.core.api.util.RiceConstants;
023import org.kuali.rice.kim.api.KimConstants;
024import org.kuali.rice.kim.api.services.KimApiServiceLocator;
025import org.kuali.rice.kns.lookup.LookupUtils;
026import org.kuali.rice.kns.lookup.Lookupable;
027import org.kuali.rice.kns.service.DocumentHelperService;
028import org.kuali.rice.kns.service.KNSServiceLocator;
029import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
030import org.kuali.rice.kns.web.struts.form.LookupForm;
031import org.kuali.rice.kns.web.ui.Field;
032import org.kuali.rice.kns.web.ui.ResultRow;
033import org.kuali.rice.kns.web.ui.Row;
034import org.kuali.rice.krad.exception.AuthorizationException;
035import org.kuali.rice.krad.lookup.CollectionIncomplete;
036import org.kuali.rice.krad.util.GlobalVariables;
037import org.kuali.rice.krad.util.KRADConstants;
038import org.kuali.rice.krad.util.KRADUtils;
039import org.springframework.web.util.HtmlUtils;
040
041import javax.servlet.ServletException;
042import javax.servlet.http.HttpServletRequest;
043import javax.servlet.http.HttpServletResponse;
044import java.io.IOException;
045import java.util.ArrayList;
046import java.util.Collection;
047import java.util.Collections;
048import java.util.HashMap;
049import java.util.Iterator;
050import java.util.Map;
051
052/**
053 * This class handles Actions for lookup flow
054 *
055 * @deprecated Use {@link org.kuali.rice.krad.lookup.LookupController}.
056 */
057@Deprecated
058public class KualiLookupAction extends KualiAction {
059    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiLookupAction.class);
060
061    @Override
062    protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
063        if (!(form instanceof LookupForm)) {
064            super.checkAuthorization(form, methodToCall);
065        } else {
066            try {
067                Class businessObjectClass = Class.forName(((LookupForm) form).getBusinessObjectClassName());
068                if (!KimApiServiceLocator.getPermissionService().isAuthorizedByTemplate(
069                        GlobalVariables.getUserSession().getPrincipalId(), KRADConstants.KNS_NAMESPACE,
070                        KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS,
071                        KRADUtils.getNamespaceAndComponentSimpleName(businessObjectClass),
072                        Collections.<String, String>emptyMap())) {
073                    throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(),
074                            KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS,
075                            businessObjectClass.getSimpleName());
076                }
077            }
078            catch (ClassNotFoundException e) {
079                LOG.warn("Unable to load BusinessObject class: " + ((LookupForm) form).getBusinessObjectClassName(), e);
080                super.checkAuthorization(form, methodToCall);
081            }
082        }
083    }
084
085    private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
086    private static DocumentHelperService documentHelperService;
087    private static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
088        if (maintenanceDocumentDictionaryService == null) {
089            maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
090        }
091        return maintenanceDocumentDictionaryService;
092    }
093    private static DocumentHelperService getDocumentHelperService() {
094        if (documentHelperService == null) {
095            documentHelperService = KNSServiceLocator.getDocumentHelperService();
096        }
097        return documentHelperService;
098    }
099    /**
100     * Checks if the user can create a document for this business object.  Used to suppress the actions on the results.
101     *
102     * @param form
103     * @return
104     * @throws ClassNotFoundException
105     */
106    protected void suppressActionsIfNeeded(ActionForm form) throws ClassNotFoundException {
107        if ((form instanceof LookupForm) && ( ((LookupForm)form).getBusinessObjectClassName() != null )) {
108            Class businessObjectClass = Class.forName( ((LookupForm)form).getBusinessObjectClassName() );
109            // check if creating documents is allowed
110            String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(businessObjectClass);
111            if ((documentTypeName != null) && !getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) {
112                ((LookupForm)form).setSuppressActions( true );
113            }
114        }
115    }
116
117    /**
118     * This method hides the criteria if set in parameter or lookupable
119     *
120     * @param form
121     */
122    private void setCriteriaEnabled(ActionForm form) {
123         LookupForm lookupForm = (LookupForm) form;
124         if(lookupForm.isLookupCriteriaEnabled()) {
125             //only overide if it's enabled, if disabled don't call lookupable
126         }
127    }
128    /**
129     * This method hides actions that are not related to the maintenance (as opposed to suppressActionsIfNeeded)
130     *
131     * @param form
132     */
133    private void suppressNonMaintActionsIfNeeded(ActionForm form) {
134        LookupForm lookupForm = (LookupForm) form;
135        if(lookupForm.getLookupable()!=null) {
136            if(StringUtils.isNotEmpty(lookupForm.getLookupable().getSupplementalMenuBar())) {
137                lookupForm.setSupplementalActionsEnabled(true);
138            }
139
140        }
141    }
142
143    @Override
144    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
145            HttpServletResponse response) throws Exception {
146        LookupForm lookupForm = (LookupForm) form;
147
148        request.setAttribute(KRADConstants.PARAM_MAINTENANCE_VIEW_MODE, KRADConstants.PARAM_MAINTENANCE_VIEW_MODE_LOOKUP);
149        suppressActionsIfNeeded(form);
150        suppressNonMaintActionsIfNeeded(form);
151        setCriteriaEnabled(form);
152
153        hideHeaderBarIfNeeded(form, request);
154
155        int numCols = KNSServiceLocator.getBusinessObjectDictionaryService().getLookupNumberOfColumns(
156                Class.forName(lookupForm.getBusinessObjectClassName()));
157        lookupForm.setNumColumns(numCols);
158
159        ActionForward forward = super.execute(mapping, form, request, response);
160
161        // apply conditional logic after all setting of field values has been completed
162        lookupForm.getLookupable().applyConditionalLogicForFieldDisplay();
163
164        return forward;
165    }
166
167    private void hideHeaderBarIfNeeded(ActionForm form, HttpServletRequest request) {
168        if (!((LookupForm) form).isHeaderBarEnabled()) {
169            ((LookupForm) form).setHeaderBarEnabled(false);
170        }
171    }
172
173
174    /**
175     * Entry point to lookups, forwards to jsp for search render.
176     */
177    public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
178        return mapping.findForward(RiceConstants.MAPPING_BASIC);
179    }
180
181    /**
182     * search - sets the values of the data entered on the form on the jsp into a map and then searches for the results.
183     */
184    public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
185        LookupForm lookupForm = (LookupForm) form;
186
187
188        String methodToCall = findMethodToCall(form, request);
189        if (methodToCall.equalsIgnoreCase("search")) {
190            GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD);
191        }
192
193
194
195        Lookupable kualiLookupable = lookupForm.getLookupable();
196        if (kualiLookupable == null) {
197            LOG.error("Lookupable is null.");
198            throw new RuntimeException("Lookupable is null.");
199        }
200
201        Collection displayList = new ArrayList();
202        ArrayList<ResultRow> resultTable = new ArrayList<ResultRow>();
203
204        // validate search parameters
205        kualiLookupable.validateSearchParameters(lookupForm.getFields());
206
207        boolean bounded = true;
208
209        displayList = kualiLookupable.performLookup(lookupForm, resultTable, bounded);
210
211        if (kualiLookupable.isSearchUsingOnlyPrimaryKeyValues()) {
212            lookupForm.setSearchUsingOnlyPrimaryKeyValues(true);
213            lookupForm.setPrimaryKeyFieldLabels(kualiLookupable.getPrimaryKeyFieldLabels());
214        }
215        else {
216            lookupForm.setSearchUsingOnlyPrimaryKeyValues(false);
217            lookupForm.setPrimaryKeyFieldLabels(KRADConstants.EMPTY_STRING);
218        }
219
220        if ( displayList instanceof CollectionIncomplete ){
221            request.setAttribute("reqSearchResultsActualSize", ((CollectionIncomplete) displayList).getActualSizeIfTruncated());
222        } else {
223            request.setAttribute("reqSearchResultsActualSize", displayList.size() );
224        }
225        
226        int resultsLimit = LookupUtils.getSearchResultsLimit(Class.forName(lookupForm.getBusinessObjectClassName()));
227        request.setAttribute("reqSearchResultsLimitedSize", resultsLimit);
228
229        // Determine if at least one table entry has an action available. If any non-breaking space (&nbsp; or '\u00A0') characters
230        // exist in the URL's value, they will be converted to regular whitespace ('\u0020').
231        boolean hasActionUrls = false;
232        for (Iterator<ResultRow> iterator = resultTable.iterator(); !hasActionUrls && iterator.hasNext();) {
233            if (StringUtils.isNotBlank(HtmlUtils.htmlUnescape(iterator.next().getActionUrls()).replace('\u00A0', '\u0020'))) {
234                hasActionUrls = true;
235            }
236        }
237        lookupForm.setActionUrlsExist(hasActionUrls);
238
239        request.setAttribute("reqSearchResults", resultTable);
240
241        if (request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY) != null) {
242            GlobalVariables.getUserSession().removeObject(request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY));
243        }
244
245        request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable, KRADConstants.SEARCH_LIST_KEY_PREFIX));
246
247        request.getParameter(KRADConstants.REFRESH_CALLER);
248
249        return mapping.findForward(RiceConstants.MAPPING_BASIC);
250    }
251
252
253    /**
254     * refresh - is called when one quickFinder returns to the previous one. Sets all the values and performs the new search.
255     */
256    @Override
257    public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
258        LookupForm lookupForm = (LookupForm) form;
259        Lookupable kualiLookupable = lookupForm.getLookupable();
260        if (kualiLookupable == null) {
261            LOG.error("Lookupable is null.");
262            throw new RuntimeException("Lookupable is null.");
263        }
264
265        if(StringUtils.equals(lookupForm.getRefreshCaller(),"customLookupAction")) {
266            return this.customLookupableMethodCall(mapping, lookupForm, request, response);
267        }
268
269        Map<String, String> fieldValues = new HashMap();
270        Map<String, String> values = lookupForm.getFields();
271
272        for (Row row: kualiLookupable.getRows()) {
273            for (Field field: row.getFields()) {
274                if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
275                    if (request.getParameter(field.getPropertyName()) != null) {
276                        if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
277                            field.setPropertyValue(request.getParameter(field.getPropertyName()));
278                        } else {
279                            //multi value, set to values
280                            field.setPropertyValues(request.getParameterValues(field.getPropertyName()));
281                        }
282                    }
283                }
284                else if (values.get(field.getPropertyName()) != null) {
285                    field.setPropertyValue(values.get(field.getPropertyName()));
286                }
287
288                kualiLookupable.applyFieldAuthorizationsFromNestedLookups(field);
289
290                fieldValues.put(field.getPropertyName(), field.getPropertyValue());
291            }
292        }
293        fieldValues.put("docFormKey", lookupForm.getFormKey());
294        fieldValues.put("backLocation", lookupForm.getBackLocation());
295        fieldValues.put("docNum", lookupForm.getDocNum());
296
297        if (kualiLookupable.checkForAdditionalFields(fieldValues)) {
298            for (Row row: kualiLookupable.getRows()) {
299                for (Object element : row.getFields()) {
300                    Field field = (Field) element;
301                    if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
302                        if (request.getParameter(field.getPropertyName()) != null) {
303//                            field.setPropertyValue(request.getParameter(field.getPropertyName()));
304                            if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
305                                field.setPropertyValue(request.getParameter(field.getPropertyName()));
306                            } else {
307                                //multi value, set to values
308                                field.setPropertyValues(request.getParameterValues(field.getPropertyName()));
309                            }
310                            //FIXME: any reason this is inside this "if" instead of the outer one, like above - this seems inconsistent
311                            fieldValues.put(field.getPropertyName(), request.getParameter(field.getPropertyName()));
312                        }
313                        else if (values.get(field.getPropertyName()) != null) {
314                            field.setPropertyValue(values.get(field.getPropertyName()));
315                        }
316                    }
317                }
318            }
319        }
320        return mapping.findForward(RiceConstants.MAPPING_BASIC);
321    }
322
323    /**
324     * Just returns as if return with no value was selected.
325     */
326    public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
327        LookupForm lookupForm = (LookupForm) form;
328
329        String backUrl = lookupForm.getBackLocation() + "?methodToCall=refresh&docFormKey=" + lookupForm.getFormKey()+"&docNum="+lookupForm.getDocNum();
330        return new ActionForward(backUrl, true);
331    }
332
333
334    /**
335     * clearValues - clears the values of all the fields on the jsp.
336     */
337    public ActionForward clearValues(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
338        LookupForm lookupForm = (LookupForm) form;
339        Lookupable kualiLookupable = lookupForm.getLookupable();
340        if (kualiLookupable == null) {
341            LOG.error("Lookupable is null.");
342            throw new RuntimeException("Lookupable is null.");
343        }
344
345        kualiLookupable.performClear(lookupForm);
346
347
348        return mapping.findForward(RiceConstants.MAPPING_BASIC);
349    }
350
351
352    public ActionForward viewResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
353        LookupForm lookupForm = (LookupForm) form;
354        if (lookupForm.isSearchUsingOnlyPrimaryKeyValues()) {
355            lookupForm.setPrimaryKeyFieldLabels(lookupForm.getLookupable().getPrimaryKeyFieldLabels());
356        }
357        // KULRICE-12281- Turn off the ability to export results from  certain lookups
358         if(StringUtils.isNotBlank(request.getParameter(KRADConstants.Lookup.VIEW_RESULTS_EXPORT_OPTION))) {
359            String componentName = Class.forName(lookupForm.getBusinessObjectClassName()).getSimpleName();
360            String principalId = GlobalVariables.getUserSession().getPrincipalId();
361            String principalUserName = GlobalVariables.getUserSession().getPrincipalName();
362            Map<String, String> permissionDetails = new HashMap<String,String>();
363            permissionDetails.put(KRADConstants.COMPONENT_NAME, componentName);
364            boolean isAuthorized = KimApiServiceLocator.getPermissionService().isAuthorizedByTemplate(
365                    principalId,KRADConstants.KNS_NAMESPACE,KimConstants.PermissionTemplateNames.VIEW_RESULTS_EXPORT_ACTION,
366                    permissionDetails,new HashMap<String,String>());
367            if(!isAuthorized){
368                throw new AuthorizationException(principalUserName, "Exporting the Lookup Results", componentName);
369            }
370         }
371        request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY));
372        request.setAttribute("reqSearchResults", GlobalVariables.getUserSession().retrieveObject(request.getParameter(
373                KRADConstants.SEARCH_LIST_REQUEST_KEY)));
374        request.setAttribute("reqSearchResultsActualSize", request.getParameter("reqSearchResultsActualSize"));
375        return mapping.findForward(RiceConstants.MAPPING_BASIC);
376    }
377
378    public ActionForward customLookupableMethodCall(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
379//      lookupableMethodToCall
380        Lookupable kualiLookupable = ((LookupForm)form).getLookupable();
381        if (kualiLookupable == null) {
382            LOG.error("Lookupable is null.");
383            throw new RuntimeException("Lookupable is null.");
384        }
385
386        boolean ignoreErrors=false;
387        if(StringUtils.equals(((LookupForm)form).getRefreshCaller(),"customLookupAction")) {
388            ignoreErrors=true;
389        }
390
391        if(kualiLookupable.performCustomAction(ignoreErrors)) {
392            //redo the search if the method comes back
393            return search(mapping, form, request, response);
394        }
395        return mapping.findForward(RiceConstants.MAPPING_BASIC);
396
397    }
398
399}