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.krad.web.controller;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.codehaus.jackson.map.ObjectMapper;
20  import org.kuali.rice.core.api.config.property.ConfigContext;
21  import org.kuali.rice.core.api.exception.RiceRuntimeException;
22  import org.kuali.rice.kim.api.identity.Person;
23  import org.kuali.rice.krad.exception.AuthorizationException;
24  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
25  import org.kuali.rice.krad.service.ModuleService;
26  import org.kuali.rice.krad.uif.UifConstants;
27  import org.kuali.rice.krad.uif.UifParameters;
28  import org.kuali.rice.krad.uif.UifPropertyPaths;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.container.Group;
31  import org.kuali.rice.krad.uif.field.AttributeQueryResult;
32  import org.kuali.rice.krad.uif.service.ViewService;
33  import org.kuali.rice.krad.uif.util.LookupInquiryUtils;
34  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
35  import org.kuali.rice.krad.uif.view.DialogManager;
36  import org.kuali.rice.krad.uif.view.MessageView;
37  import org.kuali.rice.krad.uif.view.View;
38  import org.kuali.rice.krad.util.GlobalVariables;
39  import org.kuali.rice.krad.util.KRADConstants;
40  import org.kuali.rice.krad.util.KRADUtils;
41  import org.kuali.rice.krad.util.UrlFactory;
42  import org.kuali.rice.krad.web.controller.helper.CollectionPagingHelper;
43  import org.kuali.rice.krad.web.controller.helper.DataTablesPagingHelper;
44  import org.kuali.rice.krad.web.form.HistoryFlow;
45  import org.kuali.rice.krad.web.form.HistoryManager;
46  import org.kuali.rice.krad.web.form.UifFormBase;
47  import org.kuali.rice.krad.web.form.UifFormManager;
48  import org.springframework.util.Assert;
49  import org.springframework.validation.BindingResult;
50  import org.springframework.web.bind.annotation.ModelAttribute;
51  import org.springframework.web.bind.annotation.RequestMapping;
52  import org.springframework.web.bind.annotation.RequestMethod;
53  import org.springframework.web.bind.annotation.ResponseBody;
54  import org.springframework.web.servlet.ModelAndView;
55  import org.springframework.web.servlet.support.RequestContextUtils;
56  import org.springframework.web.servlet.view.UrlBasedViewResolver;
57  
58  import javax.servlet.http.HttpServletRequest;
59  import javax.servlet.http.HttpServletResponse;
60  import java.util.Enumeration;
61  import java.util.HashMap;
62  import java.util.Map;
63  import java.util.Map.Entry;
64  import java.util.Properties;
65  
66  /**
67   * Base controller class for views within the KRAD User Interface Framework
68   *
69   * Provides common methods such as:
70   *
71   * <ul>
72   * <li>Authorization methods such as method to call check</li>
73   * <li>Preparing the View instance and setup in the returned
74   * <code>ModelAndView</code></li>
75   * </ul>
76   *
77   * All subclass controller methods after processing should call one of the
78   * #getUIFModelAndView methods to setup the <code>View</code> and return the
79   * <code>ModelAndView</code> instance.
80   *
81   * @author Kuali Rice Team (rice.collab@kuali.org)
82   */
83  public abstract class UifControllerBase {
84      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(UifControllerBase.class);
85  
86      private UrlBasedViewResolver viewResolver;
87  
88      /**
89       * Create/obtain the model(form) object before it is passed to the Binder/BeanWrapper. This method
90       * is not intended to be overridden by client applications as it handles framework setup and session
91       * maintenance. Clients should override createInitialForm() instead when they need custom form initialization.
92       *
93       * @param request the http request that was made
94       * @param response the http response object
95       */
96      @ModelAttribute(value = "KualiForm")
97      public UifFormBase initForm(HttpServletRequest request, HttpServletResponse response) {
98          UifFormBase requestForm = null;
99  
100         // get Uif form manager from session if exists or setup a new one for the session
101         UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute(UifParameters.FORM_MANAGER);
102         if (uifFormManager == null) {
103             uifFormManager = new UifFormManager();
104             request.getSession().setAttribute(UifParameters.FORM_MANAGER, uifFormManager);
105         }
106 
107         // add form manager to GlobalVariables for easy reference by other controller methods
108         GlobalVariables.setUifFormManager(uifFormManager);
109 
110         // create a new form for every request
111         requestForm = createInitialForm(request);
112 
113         String formKeyParam = request.getParameter(UifParameters.FORM_KEY);
114         if (StringUtils.isNotBlank(formKeyParam)) {
115             // retrieves the session form and updates the request from with the session transient attributes
116             uifFormManager.updateFormWithSession(requestForm, formKeyParam);
117         }
118 
119         //set the originally requested form key
120         String requestedFormKey = request.getParameter(UifParameters.REQUESTED_FORM_KEY);
121         if (StringUtils.isNotBlank(requestedFormKey)) {
122             requestForm.setRequestedFormKey(requestedFormKey);
123         } else {
124             requestForm.setRequestedFormKey(formKeyParam);
125         }
126 
127         //get the initial referer
128         String referer = request.getHeader(UifConstants.REFERER);
129 
130         //if none, set the no return flag string
131         if (StringUtils.isBlank(referer) && StringUtils.isBlank(requestForm.getReturnLocation())) {
132             requestForm.setReturnLocation(UifConstants.NO_RETURN);
133         } else if (StringUtils.isBlank(requestForm.getReturnLocation())) {
134             requestForm.setReturnLocation(referer);
135         }
136 
137         //get initial request params
138         if (requestForm.getInitialRequestParameters() == null) {
139             Map<String, String> requestParams = new HashMap<String, String>();
140             Enumeration<String> names = request.getParameterNames();
141 
142             while (names != null && names.hasMoreElements()) {
143                 String name = KRADUtils.stripXSSPatterns(names.nextElement());
144                 String value = KRADUtils.stripXSSPatterns(request.getParameter(name));
145 
146                 requestParams.put(name, value);
147             }
148 
149             requestParams.remove(UifConstants.UrlParams.LOGIN_USER);
150             requestForm.setInitialRequestParameters(requestParams);
151         }
152 
153         //set the original request url for this view/form
154         String requestUrl = KRADUtils.stripXSSPatterns(KRADUtils.getFullURL(request));
155         requestForm.setRequestUrl(requestUrl);
156 
157         Object historyManager = request.getSession().getAttribute(UifConstants.HistoryFlow.HISTORY_MANAGER);
158         String flowKey = request.getParameter(UifConstants.HistoryFlow.FLOW);
159 
160         //add history manager and current flowKey to the form
161         if (requestForm != null && historyManager != null && historyManager instanceof HistoryManager) {
162             requestForm.setHistoryManager((HistoryManager) historyManager);
163             requestForm.setFlowKey(flowKey);
164         }
165 
166         // sets the request form in the request for later retrieval
167         request.setAttribute(UifConstants.REQUEST_FORM, requestForm);
168 
169         return requestForm;
170     }
171 
172     /**
173      * Called to create a new model(form) object when necessary. This usually occurs on the initial request
174      * in a conversation (when the model is not present in the session). This method must be
175      * overridden when extending a controller and using a different form type than the superclass.
176      *
177      * @param request - the http request that was made
178      */
179     protected abstract UifFormBase createInitialForm(HttpServletRequest request);
180 
181     /**
182      * Default method mapping for cases where the method to call is not passed, calls the start method
183      */
184     @RequestMapping()
185     public ModelAndView defaultMapping(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
186             HttpServletRequest request, HttpServletResponse response) {
187         return start(form, result, request, response);
188     }
189 
190     /**
191      * Initial method called when requesting a new view instance which checks authorization and forwards
192      * the view for rendering
193      */
194     @RequestMapping(params = "methodToCall=start")
195     public ModelAndView start(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
196             HttpServletRequest request, HttpServletResponse response) {
197 
198         // check view authorization
199         // TODO: this needs to be invoked for each request
200         if (form.getView() != null) {
201             String methodToCall = request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER);
202             checkViewAuthorization(form, methodToCall);
203         }
204 
205         return getUIFModelAndView(form);
206     }
207 
208     /**
209      * Invokes the configured {@link org.kuali.rice.krad.uif.view.ViewAuthorizer} to verify the user has access to
210      * open the view. An exception is thrown if access has not been granted
211      *
212      * <p>
213      * Note this method is invoked automatically by the controller interceptor for each request
214      * </p>
215      *
216      * @param form - form instance containing the request data
217      * @param methodToCall - the request parameter 'methodToCall' which is used to determine the controller
218      * method invoked
219      */
220     public void checkViewAuthorization(UifFormBase form, String methodToCall) throws AuthorizationException {
221         // if user session not established we cannnot authorize the view request
222         if (GlobalVariables.getUserSession() == null) {
223             return;
224         }
225 
226         Person user = GlobalVariables.getUserSession().getPerson();
227 
228         boolean canOpenView = form.getView().getAuthorizer().canOpenView(form.getView(), form, user);
229         if (!canOpenView) {
230             throw new AuthorizationException(user.getPrincipalName(), "open", form.getView().getId(),
231                     "User '" + user.getPrincipalName() + "' is not authorized to open view ID: " + form.getView()
232                             .getId(), null);
233         }
234     }
235 
236     /**
237      * Invoked when a session timeout occurs, default impl does nothing but render the view
238      */
239     @RequestMapping(params = "methodToCall=sessionTimeout")
240     public ModelAndView sessionTimeout(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
241             HttpServletRequest request, HttpServletResponse response) {
242         return getUIFModelAndView(form);
243     }
244 
245     /**
246      * Called by the add line action for a new collection line. Method
247      * determines which collection the add action was selected for and invokes
248      * the view helper service to add the line
249      */
250     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=addLine")
251     public ModelAndView addLine(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
252             HttpServletRequest request, HttpServletResponse response) {
253 
254         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
255         if (StringUtils.isBlank(selectedCollectionPath)) {
256             throw new RuntimeException("Selected collection was not set for add line action, cannot add new line");
257         }
258 
259         View view = uifForm.getPostedView();
260         view.getViewHelperService().processCollectionAddLine(view, uifForm, selectedCollectionPath);
261 
262         return getUIFModelAndView(uifForm);
263     }
264 
265     /**
266      * Called by the add blank line action for a new collection line
267      *
268      * <p>
269      * Method determines which collection the add action was selected for and invokes the view helper service to
270      * add the blank line.
271      * </p>
272      *
273      * @param uifForm - form instance containing the request data
274      * @return the  ModelAndView object
275      */
276     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=addBlankLine")
277     public ModelAndView addBlankLine(@ModelAttribute("KualiForm") UifFormBase uifForm) {
278 
279         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
280         if (StringUtils.isBlank(selectedCollectionPath)) {
281             throw new RuntimeException("Selected collection was not set for add line action, cannot add new line");
282         }
283 
284         View view = uifForm.getPostedView();
285         view.getViewHelperService().processCollectionAddBlankLine(view, uifForm, selectedCollectionPath);
286 
287         return getUIFModelAndView(uifForm);
288     }
289 
290     /**
291      * Called by the save line action for a new collection line. Does server side validation and provides hook
292      * for client application to persist specific data.
293      */
294     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=saveLine")
295     public ModelAndView saveLine(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
296             HttpServletRequest request, HttpServletResponse response) {
297 
298         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
299         if (StringUtils.isBlank(selectedCollectionPath)) {
300             throw new RuntimeException("Selected collection was not set for add line action, cannot add new line");
301         }
302 
303         int selectedLineIndex = -1;
304         String selectedLine = uifForm.getActionParamaterValue(UifParameters.SELECTED_LINE_INDEX);
305         if (StringUtils.isNotBlank(selectedLine)) {
306             selectedLineIndex = Integer.parseInt(selectedLine);
307         }
308 
309         if (selectedLineIndex == -1) {
310             throw new RuntimeException("Selected line index was not set for delete line action, cannot delete line");
311         }
312 
313         View view = uifForm.getPostedView();
314         view.getViewHelperService().processCollectionSaveLine(view, uifForm, selectedCollectionPath, selectedLineIndex);
315 
316         return getUIFModelAndView(uifForm);
317     }
318 
319     /**
320      * Called by the delete line action for a model collection. Method
321      * determines which collection the action was selected for and the line
322      * index that should be removed, then invokes the view helper service to
323      * process the action
324      */
325     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=deleteLine")
326     public ModelAndView deleteLine(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
327             HttpServletRequest request, HttpServletResponse response) {
328 
329         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
330         if (StringUtils.isBlank(selectedCollectionPath)) {
331             throw new RuntimeException("Selected collection was not set for delete line action, cannot delete line");
332         }
333 
334         int selectedLineIndex = -1;
335         String selectedLine = uifForm.getActionParamaterValue(UifParameters.SELECTED_LINE_INDEX);
336         if (StringUtils.isNotBlank(selectedLine)) {
337             selectedLineIndex = Integer.parseInt(selectedLine);
338         }
339 
340         if (selectedLineIndex == -1) {
341             throw new RuntimeException("Selected line index was not set for delete line action, cannot delete line");
342         }
343 
344         View view = uifForm.getPostedView();
345         view.getViewHelperService().processCollectionDeleteLine(view, uifForm, selectedCollectionPath,
346                 selectedLineIndex);
347 
348         return getUIFModelAndView(uifForm);
349     }
350 
351     /**
352      * Just returns as if return with no value was selected.
353      */
354     @RequestMapping(params = "methodToCall=cancel")
355     public ModelAndView cancel(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
356             HttpServletRequest request, HttpServletResponse response) {
357         return back(form, result, request, response);
358     }
359 
360     /**
361      * Attempts to go back by looking at various return mechanisms in HistoryFlow and on the form.  If a back cannot
362      * be determined, returns to the application url.
363      */
364     @RequestMapping(params = "methodToCall=back")
365     public ModelAndView back(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
366             HttpServletRequest request, HttpServletResponse response) {
367         Properties props = new Properties();
368         props.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.REFRESH);
369 
370         if (StringUtils.isNotBlank(form.getReturnFormKey())) {
371             props.put(UifParameters.FORM_KEY, form.getReturnFormKey());
372         }
373 
374         HistoryFlow historyFlow = form.getHistoryManager().getMostRecentFlowByFormKey(form.getFlowKey(),
375                 form.getRequestedFormKey());
376 
377         String returnUrl = form.getReturnLocation();
378 
379         //use history flow return location
380         if (historyFlow != null) {
381             returnUrl = historyFlow.getFlowReturnPoint();
382         }
383 
384         //return to start handling
385         String returnToStart = form.getActionParamaterValue(UifConstants.HistoryFlow.RETURN_TO_START);
386         if (StringUtils.isBlank(returnToStart)) {
387             returnToStart = request.getParameter(UifConstants.HistoryFlow.RETURN_TO_START);
388         }
389 
390         if (StringUtils.isNotBlank(returnToStart)
391                 && Boolean.parseBoolean(returnToStart)
392                 && historyFlow != null
393                 && StringUtils.isNotBlank(historyFlow.getFlowStartPoint())) {
394             returnUrl = historyFlow.getFlowStartPoint();
395         }
396 
397         //return to app url if returnUrl still blank
398         if (StringUtils.isBlank(returnUrl) || returnUrl.equals(UifConstants.NO_RETURN)) {
399             returnUrl = ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.APPLICATION_URL_KEY);
400         }
401 
402         // clear current form from session
403         GlobalVariables.getUifFormManager().removeSessionForm(form);
404 
405         return performRedirect(form, returnUrl, props);
406     }
407 
408     /**
409      * Invoked to navigate back one page in history..
410      *
411      * @param form - form object that should contain the history object
412      */
413     @RequestMapping(params = "methodToCall=returnToPrevious")
414     public ModelAndView returnToPrevious(@ModelAttribute("KualiForm") UifFormBase form) {
415 
416         return returnToHistory(form, false);
417     }
418 
419     /**
420      * Invoked to navigate back to the first page in history.
421      *
422      * @param form - form object that should contain the history object
423      */
424     @RequestMapping(params = "methodToCall=returnToHub")
425     public ModelAndView returnToHub(@ModelAttribute("KualiForm") UifFormBase form) {
426 
427         return returnToHistory(form, true);
428     }
429 
430     /**
431      * Invoked to navigate back to a history entry. The homeFlag will determine whether navigation
432      * will be back to the first or last history entry.
433      *
434      * @param form - form object that should contain the history object
435      * @param homeFlag - if true will navigate back to first entry else will navigate to last entry
436      * in the history
437      */
438     public ModelAndView returnToHistory(UifFormBase form, boolean homeFlag) {
439         String returnUrl = form.getReturnLocation();
440 
441         if (StringUtils.isBlank(returnUrl) || homeFlag) {
442             returnUrl = ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.APPLICATION_URL_KEY);
443         }
444 
445         // Add the refresh call
446         Properties props = new Properties();
447         props.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.REFRESH);
448 
449         // clear current form from session
450         GlobalVariables.getUifFormManager().removeSessionForm(form);
451 
452         return performRedirect(form, returnUrl, props);
453     }
454 
455     /**
456      * Handles menu navigation between view pages
457      */
458     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=navigate")
459     public ModelAndView navigate(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
460             HttpServletRequest request, HttpServletResponse response) {
461         String pageId = form.getActionParamaterValue(UifParameters.NAVIGATE_TO_PAGE_ID);
462 
463         //clear dirty flag, if set
464         form.setDirtyForm(false);
465 
466         return getUIFModelAndView(form, pageId);
467     }
468 
469     /**
470      * handles an ajax refresh
471      *
472      * <p>The query form plugin  activates this request via a form post, where on the JS side,
473      * {@code org.kuali.rice.krad.uif.UifParameters#RENDER_FULL_VIEW} is set to false</p>
474      *
475      * @param form -  Holds properties necessary to determine the <code>View</code> instance that will be used to
476      * render
477      * the UI
478      * @param result -   represents binding results
479      * @param request - http servlet request data
480      * @param response - http servlet response object
481      * @return the  ModelAndView object
482      * @throws Exception
483      */
484     @RequestMapping(params = "methodToCall=refresh")
485     public ModelAndView refresh(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
486             HttpServletRequest request, HttpServletResponse response) throws Exception {
487         // TODO: this code still needs to handle reference refreshes
488 
489         String flashMapSelectedLineValues = "";
490         if (RequestContextUtils.getInputFlashMap(request) != null) {
491             flashMapSelectedLineValues = (String) RequestContextUtils.getInputFlashMap(request).get(
492                     UifParameters.SELECTED_LINE_VALUES);
493         }
494         String refreshCallerType = "";
495         if (request.getParameterMap().containsKey(KRADConstants.REFRESH_CALLER_TYPE)) {
496             refreshCallerType = request.getParameter(KRADConstants.REFRESH_CALLER_TYPE);
497         }
498 
499         // process multi-value lookup returns
500         if (StringUtils.equals(refreshCallerType, UifConstants.RefreshCallerTypes.MULTI_VALUE_LOOKUP)) {
501             String lookupCollectionName = "";
502             if (request.getParameterMap().containsKey(UifParameters.LOOKUP_COLLECTION_NAME)) {
503                 lookupCollectionName = request.getParameter(UifParameters.LOOKUP_COLLECTION_NAME);
504             }
505 
506             if (StringUtils.isBlank(lookupCollectionName)) {
507                 throw new RuntimeException(
508                         "Lookup collection name is required for processing multi-value lookup results");
509             }
510 
511             String selectedLineValues = "";
512             if (request.getParameterMap().containsKey(UifParameters.SELECTED_LINE_VALUES)) {
513                 selectedLineValues = request.getParameter(UifParameters.SELECTED_LINE_VALUES);
514             }
515             if (!StringUtils.isBlank(flashMapSelectedLineValues)) {
516                 selectedLineValues = flashMapSelectedLineValues;
517             }
518 
519             // invoked view helper to populate the collection from lookup results
520             form.getPostedView().getViewHelperService().processMultipleValueLookupResults(form.getPostedView(), form,
521                     lookupCollectionName, selectedLineValues);
522         }
523 
524         if (request.getParameterMap().containsKey(KRADConstants.REFERENCES_TO_REFRESH)) {
525             String referencesToRefresh = request.getParameter(KRADConstants.REFERENCES_TO_REFRESH);
526             form.getPostedView().getViewHelperService().refreshReferences(form, referencesToRefresh);
527         }
528 
529         return getUIFModelAndView(form);
530     }
531 
532     /**
533      * Builds up a URL to the lookup view based on the given post action
534      * parameters and redirects
535      */
536     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=performLookup")
537     public ModelAndView performLookup(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
538             HttpServletRequest request, HttpServletResponse response) {
539         Properties lookupParameters = form.getActionParametersAsProperties();
540 
541         String lookupObjectClassName = (String) lookupParameters.get(UifParameters.DATA_OBJECT_CLASS_NAME);
542         Class<?> lookupObjectClass = null;
543         try {
544             lookupObjectClass = Class.forName(lookupObjectClassName);
545         } catch (ClassNotFoundException e) {
546             LOG.error("Unable to get class for name: " + lookupObjectClassName);
547             throw new RuntimeException("Unable to get class for name: " + lookupObjectClassName, e);
548         }
549 
550         // get form values for the lookup parameter fields
551         String lookupParameterString = (String) lookupParameters.get(UifParameters.LOOKUP_PARAMETERS);
552         if (lookupParameterString != null) {
553             Map<String, String> lookupParameterFields = KRADUtils.getMapFromParameterString(lookupParameterString);
554             for (Entry<String, String> lookupParameter : lookupParameterFields.entrySet()) {
555                 String lookupParameterValue = LookupInquiryUtils.retrieveLookupParameterValue(form, request,
556                         lookupObjectClass, lookupParameter.getValue(), lookupParameter.getKey());
557 
558                 if (StringUtils.isNotBlank(lookupParameterValue)) {
559                     lookupParameters.put(UifPropertyPaths.LOOKUP_CRITERIA + "['" + lookupParameter.getValue() + "']",
560                             lookupParameterValue);
561                 }
562             }
563 
564             lookupParameters.remove(UifParameters.LOOKUP_PARAMETERS);
565         }
566 
567         // TODO: lookup anchors and doc number?
568 
569         String baseLookupUrl = (String) lookupParameters.get(UifParameters.BASE_LOOKUP_URL);
570         lookupParameters.remove(UifParameters.BASE_LOOKUP_URL);
571 
572         // set lookup method to call
573         lookupParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.START);
574         String autoSearchString = (String) lookupParameters.get(UifParameters.AUTO_SEARCH);
575         if (Boolean.parseBoolean(autoSearchString)) {
576             lookupParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.SEARCH);
577         }
578 
579         lookupParameters.put(UifParameters.RETURN_LOCATION, form.getFormPostUrl());
580         lookupParameters.put(UifParameters.RETURN_FORM_KEY, form.getFormKey());
581 
582         // special check for external object classes
583         if (lookupObjectClass != null) {
584             ModuleService responsibleModuleService =
585                     KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(lookupObjectClass);
586             if (responsibleModuleService != null && responsibleModuleService.isExternalizable(lookupObjectClass)) {
587                 String lookupUrl = responsibleModuleService.getExternalizableDataObjectLookupUrl(lookupObjectClass,
588                         lookupParameters);
589 
590                 return performRedirect(form, lookupUrl, new Properties());
591             }
592         }
593 
594         return performRedirect(form, baseLookupUrl, lookupParameters);
595     }
596 
597     /**
598      * Checks the form/view against all current and future validations and returns warnings for any validations
599      * that fail
600      */
601     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=checkForm")
602     public ModelAndView checkForm(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
603             HttpServletRequest request, HttpServletResponse response) {
604         KRADServiceLocatorWeb.getViewValidationService().validateViewSimulation(form.getPostedView(), form);
605 
606         return getUIFModelAndView(form);
607     }
608 
609     /**
610      * Invoked to provide the options for a suggest widget. The valid options are retrieved by the associated
611      * <code>AttributeQuery</code> for the field containing the suggest widget. The controller method picks
612      * out the query parameters from the request and calls <code>AttributeQueryService</code> to perform the
613      * suggest query and prepare the result object that will be exposed with JSON
614      */
615     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=performFieldSuggest")
616     public
617     @ResponseBody
618     AttributeQueryResult performFieldSuggest(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
619             HttpServletRequest request, HttpServletResponse response) {
620 
621         // retrieve query fields from request
622         Map<String, String> queryParameters = new HashMap<String, String>();
623         for (Object parameterName : request.getParameterMap().keySet()) {
624             if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETER + ".")) {
625                 String fieldName = StringUtils.substringAfter(parameterName.toString(),
626                         UifParameters.QUERY_PARAMETER + ".");
627                 String fieldValue = request.getParameter(parameterName.toString());
628                 queryParameters.put(fieldName, fieldValue);
629             }
630         }
631 
632         // retrieve id for field to perform query for
633         String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID);
634         if (StringUtils.isBlank(queryFieldId)) {
635             throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: "
636                     + UifParameters.QUERY_FIELD_ID);
637         }
638 
639         // get the field term to match
640         String queryTerm = request.getParameter(UifParameters.QUERY_TERM);
641         if (StringUtils.isBlank(queryTerm)) {
642             throw new RuntimeException(
643                     "Unable to find id for query term value for attribute query on under request parameter name: "
644                             + UifParameters.QUERY_TERM);
645         }
646 
647         // invoke attribute query service to perform the query
648         AttributeQueryResult queryResult = KRADServiceLocatorWeb.getAttributeQueryService().performFieldSuggestQuery(
649                 form.getPostedView(), queryFieldId, queryTerm, queryParameters);
650 
651         return queryResult;
652     }
653 
654     /**
655      * Invoked to execute the <code>AttributeQuery</code> associated with a field given the query parameters
656      * found in the request. This controller method picks out the query parameters from the request and calls
657      * <code>AttributeQueryService</code> to perform the field query and prepare the result object
658      * that will be exposed with JSON. The result is then used to update field values in the UI with client
659      * script.
660      */
661     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=performFieldQuery")
662     public
663     @ResponseBody
664     AttributeQueryResult performFieldQuery(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
665             HttpServletRequest request, HttpServletResponse response) {
666 
667         // retrieve query fields from request
668         Map<String, String> queryParameters = new HashMap<String, String>();
669         for (Object parameterName : request.getParameterMap().keySet()) {
670             if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETER + ".")) {
671                 String fieldName = StringUtils.substringAfter(parameterName.toString(),
672                         UifParameters.QUERY_PARAMETER + ".");
673                 String fieldValue = request.getParameter(parameterName.toString());
674                 queryParameters.put(fieldName, fieldValue);
675             }
676         }
677 
678         // retrieve id for field to perform query for
679         String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID);
680         if (StringUtils.isBlank(queryFieldId)) {
681             throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: "
682                     + UifParameters.QUERY_FIELD_ID);
683         }
684 
685         // invoke attribute query service to perform the query
686         AttributeQueryResult queryResult = KRADServiceLocatorWeb.getAttributeQueryService().performFieldQuery(
687                 form.getPostedView(), queryFieldId, queryParameters);
688 
689         return queryResult;
690     }
691 
692     /**
693      * returns whether this dialog has been displayed on the client
694      *
695      * @param dialogId - the id of the dialog
696      * @param form - form instance containing the request data
697      * @return boolean - true if dialog has been displayed, false if not
698      */
699     protected boolean hasDialogBeenDisplayed(String dialogId, UifFormBase form) {
700         return (form.getDialogManager().hasDialogBeenDisplayed(dialogId));
701     }
702 
703     /**
704      * returns whether the dialog has already been answered by the user
705      *
706      * @param dialogId - identifier for the dialog group
707      * @param form - form instance containing the request data
708      * @return boolean - true if client has already responded to the dialog, false otherwise
709      */
710     protected boolean hasDialogBeenAnswered(String dialogId, UifFormBase form) {
711         return (form.getDialogManager().hasDialogBeenAnswered(dialogId));
712     }
713 
714     /**
715      * Sets the status of the dialog tracking record to indicate that this dialog
716      * has not yet been asked or answered
717      *
718      * @param dialogId  - the id of the dialog
719      * @param form - form instance containing the request data
720      */
721     protected void resetDialogStatus(String dialogId, UifFormBase form) {
722         form.getDialogManager().resetDialogStatus(dialogId);
723     }
724 
725     /**
726      * Handles a modal dialog interaction with the client user when a @{boolean} response is desired
727      *
728      * <p>
729      * If this modal dialog has not yet been presented to the user, a runtime exception is thrown.   Use the following
730      * code in the view controller to ensure the dialog has been displayed and answered:
731      * <pre>{@code
732      *  DialogManager dm = form.getDialogManager();
733      *  if (!dm.hasDialogBeenAnswered(dialogId)) {
734      *      return showDialog(dialogId, form, request, response);
735      *  }
736      *  answer = getBooleanDialogResponse(dialogId, form, request, response);
737      * }</pre>
738      * </p>
739      *
740      * <p>
741      * If the dialog has already been answered by the user.  The boolean value representing the
742      * option chosen by the user is returned back to the calling controller
743      * </p>
744      *
745      * @param dialogId - identifier of the dialog group
746      * @param form - form instance containing the request data
747      * @param request - the http request
748      * @param response - the http response
749      * @return boolean - true if user chose affirmative response, false if negative response was chosen
750      * @throws RiceRuntimeException when dialog has not been answered.
751      */
752     protected boolean getBooleanDialogResponse(String dialogId, UifFormBase form, HttpServletRequest request,
753             HttpServletResponse response) {
754         DialogManager dm = form.getDialogManager();
755         if (!dm.hasDialogBeenAnswered(dialogId)) {
756 
757             // ToDo: It would be nice if showDialog could be called here and avoid this exception.
758             //       This would also remove the need of having to call showDialog explicitly.
759 
760             throw new RiceRuntimeException("Dialog has not yet been answered by client. "
761                     + "Check that hasDialogBeenAnswered(id) returns true.");
762         }
763 
764         return dm.wasDialogAnswerAffirmative(dialogId);
765     }
766 
767     /**
768      * Handles a modal dialog interaction with the client user when a @{code String} response is desired
769      *
770      * <p>
771      * If this modal dialog has not yet been presented to the user, a runtime exception is thrown.   Use the following
772      * code in the view controller to ensure the dialog has been displayed and answered:
773      * <pre>{@code
774      *  DialogManager dm = form.getDialogManager();
775      *  if (!dm.hasDialogBeenAnswered(dialogId)) {
776      *      return showDialog(dialogId, form, request, response);
777      *  }
778      *  answer = getBooleanDialogResponse(dialogId, form, request, response);
779      * }</pre>
780      * </p>
781      *
782      * <p>
783      * If the dialog has already been answered by the user.  The string value is the key string of the key/value pair
784      * assigned to the button that the user chose.
785      * </p>
786      *
787      * @param dialogId - identifier of the dialog group
788      * @param form - form instance containing the request data
789      * @param request - the http request
790      * @param response - the http response
791      * @return the key string of the response button
792      * @throws RiceRuntimeException when dialog has not been answered.
793      */
794 
795     protected String getStringDialogResponse(String dialogId, UifFormBase form, HttpServletRequest request,
796             HttpServletResponse response) {
797         DialogManager dm = form.getDialogManager();
798         if (!dm.hasDialogBeenAnswered(dialogId)) {
799             // ToDo: It would be nice if showDialog could be called here and avoid this exception.
800             //       This would also remove the need of having to call showDialog explicitly.
801 
802             throw new RiceRuntimeException("Dialog has not yet been answered by client. "
803                     + "Check that hasDialogBeenAnswered(id) returns true.");
804         }
805 
806         return dm.getDialogAnswer(dialogId);
807     }
808 
809     /**
810      * Complete the response directly and launch lightbox with dialog content upon returning back to the client. If it
811      * is an ajax request then set the ajaxReturnType and set the updateComponentId to the dialogId.
812      *
813      * <p>
814      * Need to build up the view/component properly as we would if we returned normally back to the DispatcherServlet
815      * from the controller method.
816      * </p>
817      *
818      * @param dialogId - id of the dialog or group to use as content in the lightbox.
819      * @param form - the form associated with the view
820      * @param request - the http request
821      * @param response - the http response
822      * @return will return void.  actually, won't return at all.
823      * @throws Exception
824      */
825     protected ModelAndView showDialog(String dialogId, UifFormBase form, HttpServletRequest request,
826             HttpServletResponse response) {
827         // js script to invoke lightbox: runs onDocumentReady
828         form.setLightboxScript("openLightboxOnLoad('" + dialogId + "');");
829         form.getDialogManager().addDialog(dialogId, form.getMethodToCall());
830 
831         // if the dialog is being invoked sever side via ajax set the ajaxReturnType to update-dialog
832         // and set the updateComponentId to the dialogId
833         if (form.isAjaxRequest()) {
834             form.setAjaxReturnType(UifConstants.AjaxReturnTypes.UPDATEDIALOG.getKey());
835             form.setUpdateComponentId(dialogId);
836         }
837 
838         return getUIFModelAndView(form);
839     }
840 
841     /**
842      * Common return point for dialogs
843      *
844      * <p>
845      * Determines the user responses to the dialog. Performs dialog management and then redirects to the
846      * original contoller method.
847      * </p>
848      *
849      * @param form - current form
850      * @param result - binding result
851      * @param request - http request
852      * @param response - http response
853      * @return ModelAndView setup for redirect to original controller methodToCall
854      * @throws Exception
855      */
856     @RequestMapping(params = "methodToCall=returnFromLightbox")
857     public ModelAndView returnFromLightbox(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
858             HttpServletRequest request, HttpServletResponse response) {
859         String newMethodToCall = "";
860 
861         // Save user responses from dialog
862         DialogManager dm = form.getDialogManager();
863         String dialogId = dm.getCurrentDialogId();
864         if (dialogId == null) {
865             // may have been invoked by client.
866             // TODO:  handle this case (scheduled for 2.2-m3)
867             // for now, log WARNING and default to start, can we add a growl?
868             newMethodToCall = "start";
869         } else {
870             dm.setDialogAnswer(dialogId, form.getDialogResponse());
871             dm.setDialogExplanation(dialogId, form.getDialogExplanation());
872             newMethodToCall = dm.getDialogReturnMethod(dialogId);
873             dm.setCurrentDialogId(null);
874         }
875 
876         // call intended controller method
877         Properties props = new Properties();
878         props.put(UifParameters.METHOD_TO_CALL, newMethodToCall);
879         props.put(UifParameters.VIEW_ID, form.getViewId());
880         props.put(UifParameters.FORM_KEY, form.getFormKey());
881         props.put(UifParameters.AJAX_REQUEST, "false");
882 
883         return performRedirect(form, form.getFormPostUrl(), props);
884     }
885 
886     /**
887      * Builds a <code>ModelAndView</code> instance configured to redirect to the
888      * URL formed by joining the base URL with the given URL parameters
889      *
890      * @param form current form instance
891      * @param baseUrl base url to redirect to
892      * @param urlParameters properties containing key/value pairs for the url parameters, if null or empty,
893      * the baseUrl will be used as the full URL
894      * @return ModelAndView configured to redirect to the given URL
895      */
896     protected ModelAndView performRedirect(UifFormBase form, String baseUrl, Properties urlParameters) {
897         String redirectUrl = UrlFactory.parameterizeUrl(baseUrl, urlParameters);
898 
899         return performRedirect(form, redirectUrl);
900     }
901 
902     /**
903      * Builds a <code>ModelAndView</code> instance configured to redirect to the given URL
904      *
905      * @param form current form instance
906      * @param redirectUrl URL to redirect to
907      * @return ModelAndView configured to redirect to the given URL
908      */
909     protected ModelAndView performRedirect(UifFormBase form, String redirectUrl) {
910         // indicate a redirect is occuring to prevent view processing down the line
911         form.setRequestRedirected(true);
912 
913         // set the ajaxReturnType on the form this will override the return type requested by the client
914         form.setAjaxReturnType(UifConstants.AjaxReturnTypes.REDIRECT.getKey());
915 
916         ModelAndView modelAndView;
917         if (form.isAjaxRequest()) {
918             modelAndView = getUIFModelAndView(form, form.getPageId());
919             modelAndView.addObject("redirectUrl", redirectUrl);
920         } else {
921             modelAndView = new ModelAndView(UifConstants.REDIRECT_PREFIX + redirectUrl);
922         }
923 
924         return modelAndView;
925     }
926 
927     /**
928      * Builds a message view from the given header and message text then forwards the UIF model and view
929      *
930      * <p>
931      * If an error or other type of interruption occurs during the request processing the controller can
932      * invoke this message to display the message to the user. This will abandon the view that was requested
933      * and display a view with just the message
934      * </p>
935      *
936      * @param form UIF form instance
937      * @param headerText header text for the message view (can be blank)
938      * @param messageText text for the message to display
939      * @return ModelAndView
940      */
941     protected ModelAndView getMessageView(UifFormBase form, String headerText, String messageText) {
942         // get a new message view
943         MessageView messageView = (MessageView) getViewService().getViewById(UifConstants.MESSAGE_VIEW_ID);
944 
945         messageView.setHeaderText(headerText);
946         messageView.setMessageText(messageText);
947 
948         form.setViewId(UifConstants.MESSAGE_VIEW_ID);
949         form.setView(messageView);
950 
951         return getUIFModelAndView(form);
952     }
953 
954     /**
955      * Configures the <code>ModelAndView</code> instance containing the form
956      * data and pointing to the UIF generic spring view
957      *
958      * @param form form instance containing the model data
959      * @return ModelAndView object with the contained form
960      */
961     protected ModelAndView getUIFModelAndView(UifFormBase form) {
962         return getUIFModelAndView(form, form.getPageId());
963     }
964 
965     /**
966      * Configures the <code>ModelAndView</code> instance containing the form
967      * data and pointing to the UIF generic spring view
968      *
969      * @param form form instance containing the model data
970      * @param pageId id of the page within the view that should be rendered, can
971      * be left blank in which the current or default page is rendered
972      * @return ModelAndView object with the contained form
973      */
974     protected ModelAndView getUIFModelAndView(UifFormBase form, String pageId) {
975         return UifControllerHelper.getUIFModelAndView(form, pageId);
976     }
977 
978     /**
979      * Retrieves a new view instance for the given view id and then configures the <code>ModelAndView</code>
980      * instance containing the form data and pointing to the UIF generic spring view
981      *
982      * @param form form instance containing the model data
983      * @param viewId id for the view that should be built
984      * @return ModelAndView object with the contained form
985      */
986     protected ModelAndView getUIFModelAndViewWithInit(UifFormBase form, String viewId) {
987         View view = getViewService().getViewById(viewId);
988 
989         Assert.notNull(view, "View not found with id: " + viewId);
990 
991         form.setView(view);
992         form.setViewId(viewId);
993 
994         return UifControllerHelper.getUIFModelAndView(form, form.getPageId());
995     }
996 
997     /**
998      * Configures the <code>ModelAndView</code> instance containing the form data and pointing to the UIF
999      * generic spring view, additional attributes may be exposed to the view through the map argument
1000      *
1001      * @param form form instance containing the model data
1002      * @param additionalViewAttributes map of additional attributes to expose, key will be string the object
1003      * is exposed under
1004      * @return ModelAndView object with the contained form
1005      */
1006     protected ModelAndView getUIFModelAndView(UifFormBase form, Map<String, Object> additionalViewAttributes) {
1007         ModelAndView modelAndView = UifControllerHelper.getUIFModelAndView(form, form.getPageId());
1008 
1009         if (additionalViewAttributes != null) {
1010             for (Map.Entry<String, Object> additionalViewAttribute : additionalViewAttributes.entrySet()) {
1011                 modelAndView.getModelMap().put(additionalViewAttribute.getKey(), additionalViewAttribute.getValue());
1012             }
1013         }
1014 
1015         return modelAndView;
1016     }
1017 
1018     protected ViewService getViewService() {
1019         return KRADServiceLocatorWeb.getViewService();
1020     }
1021 
1022     /**
1023      * Generates exportable table data as CSV based on the rich table selected
1024      *
1025      * @param form - current form
1026      * @param result - binding result
1027      * @param request - http request
1028      * @param response - http response
1029      * @return
1030      */
1031     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_CSV,
1032             produces = {"text/csv"})
1033     @ResponseBody
1034     public String tableCsvRetrieval(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1035             HttpServletRequest request, HttpServletResponse response) {
1036         LOG.debug("processing csv table data request");
1037 
1038         return retrieveTableData(form, result, request, response);
1039     }
1040 
1041     /**
1042      * Generates exportable table data in xsl based on the rich table selected
1043      *
1044      * @param form - current form
1045      * @param result - binding result
1046      * @param request - http request
1047      * @param response - http response
1048      * @return
1049      */
1050     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_XLS,
1051             produces = {"application/vnd.ms-excel"})
1052     @ResponseBody
1053     public String tableXlsRetrieval(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1054             HttpServletRequest request, HttpServletResponse response) {
1055         LOG.debug("processing xls table data request");
1056 
1057         return retrieveTableData(form, result, request, response);
1058     }
1059 
1060     /**
1061      * Generates exportable table data based on the rich table selected
1062      *
1063      * @param form - current form
1064      * @param result - binding result
1065      * @param request - http request
1066      * @param response - http response
1067      * @return
1068      */
1069     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_XML,
1070             produces = {"application/xml"})
1071     @ResponseBody
1072     public String tableXmlRetrieval(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1073             HttpServletRequest request, HttpServletResponse response) {
1074         LOG.debug("processing xml table data request");
1075 
1076         return retrieveTableData(form, result, request, response);
1077     }
1078 
1079     /**
1080      * Generates exportable table data based on the rich table selected
1081      */
1082     private String retrieveTableData(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1083             HttpServletRequest request, HttpServletResponse response) {
1084         LOG.debug("processing table data request");
1085 
1086         String tableData = "";
1087         String formatType = getValidatedFormatType(request.getParameter("formatType"));
1088         String contentType = getContentType(formatType);
1089 
1090         UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute(UifParameters.FORM_MANAGER);
1091         String formKey = request.getParameter(UifParameters.FORM_KEY);
1092         String tableId = request.getParameter(UifParameters.TABLE_ID);
1093         UifFormBase currentForm = uifFormManager.getSessionForm(formKey);
1094         View view;
1095         if (currentForm.getPostedView() != null) {
1096             view = currentForm.getPostedView();
1097         } else {
1098             view = currentForm.getView();
1099         }
1100 
1101         LOG.debug("identifying table from model and form");
1102         tableData = view.getViewHelperService().buildExportTableData(view, currentForm, tableId, formatType);
1103 
1104         // if table data to be returned, format response appropriately
1105         response.setHeader("content-type", contentType);
1106         response.setHeader("Content-disposition", "attachment; filename=\"export." + formatType + "\"");
1107         response.setHeader("Expires", "0");
1108         response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
1109         response.setHeader("Pragma", "public");
1110 
1111         return tableData;
1112     }
1113 
1114     /**
1115      * Retrieve a page defined by the page number parameter for a collection
1116      *
1117      * @param form -  Holds properties necessary to determine the <code>View</code> instance that will be used to
1118      * render
1119      * the UI
1120      * @param result -   represents binding results
1121      * @param request - http servlet request data
1122      * @param response - http servlet response object
1123      * @return the  ModelAndView object
1124      * @throws Exception
1125      */
1126     @RequestMapping(params = "methodToCall=retrieveCollectionPage")
1127     public ModelAndView retrieveCollectionPage(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1128             HttpServletRequest request, HttpServletResponse response) throws Exception {
1129         String collectionId = request.getParameter(UifParameters.UPDATE_COMPONENT_ID);
1130         String pageNumber = request.getParameter(UifConstants.PageRequest.PAGE_NUMBER);
1131 
1132         CollectionPagingHelper pagingHelper = new CollectionPagingHelper();
1133         pagingHelper.processPagingRequest(form.getPostedView(), collectionId, form, pageNumber);
1134 
1135         return getUIFModelAndView(form);
1136     }
1137 
1138     /**
1139      * Retrieves the original component as it exists in postedView without attempting to refresh it; fast and
1140      * consistent when this is all that is needed
1141      *
1142      * <p>By passing in the "changeProperties" parameter to this controller method, properties can be changed on
1143      * the retrieved component.  However, keep in mind that since this method does not call the lifecycle on
1144      * the returned component, properties which require a lifecycle to be run to affect the output of a component
1145      * should not be set.  Main use case is to affect attributes which are only used by the ftl.  The
1146      * "changeProperties" parameter must be in JSON in string from, ie "{\"propertyPath\": true}"; note the use
1147      * of escaping, as this is required.  The propertyPath defines the property on the component that needs to be
1148      * changed during this retrieval.  This call must be using the "update-component" return type.</p>
1149      *
1150      * @param form -  Holds properties necessary to determine the <code>View</code> instance that will be used to
1151      * render
1152      * the UI
1153      * @param result -   represents binding results
1154      * @param request - http servlet request data
1155      * @param response - http servlet response object
1156      * @return the  ModelAndView object
1157      * @throws Exception
1158      */
1159     @RequestMapping(params = "methodToCall=retrieveOriginalComponent")
1160     public ModelAndView retrieveOriginalComponent(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1161             HttpServletRequest request, HttpServletResponse response) throws Exception {
1162         String componentId = request.getParameter(UifParameters.UPDATE_COMPONENT_ID);
1163         form.setOriginalComponentRequest(true);
1164 
1165         return getUIFModelAndView(form);
1166     }
1167 
1168     /**
1169      * Reviews and returns a valid format type, defaults to csv
1170      *
1171      * @param formatType
1172      * @return
1173      */
1174     private String getValidatedFormatType(String formatType) {
1175         if ("xls".equals(formatType) || "xml".equals(formatType) || "csv".equals(formatType)) {
1176             return formatType;
1177         }
1178         return "csv";
1179     }
1180 
1181     /**
1182      * Reviews and returns a valid content type, defaults to text/csv
1183      *
1184      * @param formatType
1185      * @return
1186      */
1187     private String getContentType(String formatType) {
1188         if ("csv".equals(formatType)) {
1189             return "text/csv";
1190         } else if ("xls".equals(formatType)) {
1191             return "application/vnd.ms-excel";
1192         } else if ("xml".equals(formatType)) {
1193             return "application/xml";
1194         }
1195         return "text/csv";
1196     }
1197 
1198     /**
1199      * Get method for getting aaData for jquery datatables which are using sAjaxSource option.
1200      *
1201      * <p>This will render the aaData JSON for the displayed page of the table matching the tableId passed in the
1202      * request parameters.</p>
1203      */
1204     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=tableJsonRetrieval")
1205     public ModelAndView tableJsonRetrieval(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1206             HttpServletRequest request, HttpServletResponse response) {
1207         String tableId = request.getParameter(UifParameters.TABLE_ID);
1208 
1209         DataTablesPagingHelper.DataTablesInputs dataTablesInputs = new DataTablesPagingHelper.DataTablesInputs(request);
1210 
1211         DataTablesPagingHelper pagingHelper = createDataTablesPagingHelperInstance(form, request);
1212         pagingHelper.processPagingRequest(form.getPostedView(), tableId, form, dataTablesInputs);
1213 
1214         Map<String, Object> additionalViewAttributes = new HashMap<String, Object>();
1215         additionalViewAttributes.put(UifParameters.DATA_TABLES_PAGING_HELPER, pagingHelper);
1216 
1217         return getUIFModelAndView(form, additionalViewAttributes);
1218     }
1219 
1220     /**
1221      * Creates a DataTablesPagingHelper which is used within {@link #tableJsonRetrieval(org.kuali.rice.krad.web.form.UifFormBase,
1222      * org.springframework.validation.BindingResult, javax.servlet.http.HttpServletRequest,
1223      * javax.servlet.http.HttpServletResponse)}
1224      * for rendering pages of data in JSON form.
1225      *
1226      * <p>This template method can be overridden to supply a custom extension of DataTablesPagingHelper e.g. for paging
1227      * and sorting at the data layer.</p>
1228      *
1229      * @return the DataTablesPagingHelper instance
1230      */
1231     protected DataTablesPagingHelper createDataTablesPagingHelperInstance(UifFormBase form,
1232             HttpServletRequest request) {
1233         return new DataTablesPagingHelper();
1234     }
1235 }