View Javadoc

1   /**
2    * Copyright 2005-2012 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.kuali.rice.core.api.config.property.ConfigContext;
20  import org.kuali.rice.core.web.format.BooleanFormatter;
21  import org.kuali.rice.kim.api.identity.Person;
22  import org.kuali.rice.krad.exception.AuthorizationException;
23  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24  import org.kuali.rice.krad.service.ModuleService;
25  import org.kuali.rice.krad.service.SessionDocumentService;
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.CollectionGroup;
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.ComponentFactory;
34  import org.kuali.rice.krad.uif.util.LookupInquiryUtils;
35  import org.kuali.rice.krad.uif.util.UifFormManager;
36  import org.kuali.rice.krad.uif.util.UifWebUtils;
37  import org.kuali.rice.krad.uif.view.History;
38  import org.kuali.rice.krad.uif.view.HistoryEntry;
39  import org.kuali.rice.krad.uif.view.View;
40  import org.kuali.rice.krad.util.GlobalVariables;
41  import org.kuali.rice.krad.util.KRADConstants;
42  import org.kuali.rice.krad.util.KRADUtils;
43  import org.kuali.rice.krad.util.UrlFactory;
44  import org.kuali.rice.krad.web.form.UifFormBase;
45  import org.springframework.validation.BindingResult;
46  import org.springframework.web.bind.annotation.ModelAttribute;
47  import org.springframework.web.bind.annotation.RequestMapping;
48  import org.springframework.web.bind.annotation.RequestMethod;
49  import org.springframework.web.bind.annotation.ResponseBody;
50  import org.springframework.web.servlet.ModelAndView;
51  
52  import javax.servlet.http.HttpServletRequest;
53  import javax.servlet.http.HttpServletResponse;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.Map.Entry;
58  import java.util.Properties;
59  
60  /**
61   * Base controller class for views within the KRAD User Interface Framework
62   *
63   * Provides common methods such as:
64   *
65   * <ul>
66   * <li>Authorization methods such as method to call check</li>
67   * <li>Preparing the View instance and setup in the returned
68   * <code>ModelAndView</code></li>
69   * </ul>
70   *
71   * All subclass controller methods after processing should call one of the
72   * #getUIFModelAndView methods to setup the <code>View</code> and return the
73   * <code>ModelAndView</code> instance.
74   *
75   * @author Kuali Rice Team (rice.collab@kuali.org)
76   */
77  public abstract class UifControllerBase {
78      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(UifControllerBase.class);
79  
80      protected static final String REDIRECT_PREFIX = "redirect:";
81  
82      /**
83       * Create/obtain the model(form) object before it is passed to the Binder/BeanWrapper. This method
84       * is not intended to be overridden by client applications as it handles framework setup and session
85       * maintenance. Clients should override createIntialForm() instead when they need custom form initialization.
86       *
87       * @param request - the http request that was made
88       */
89      @ModelAttribute(value = "KualiForm")
90      public final UifFormBase initForm(HttpServletRequest request) {
91          UifFormBase form = null;
92  
93          // get Uif form manager from session if exists or setup a new one for the session
94          UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute(
95                  UifParameters.FORM_MANAGER);
96          if (uifFormManager == null) {
97              uifFormManager = new UifFormManager();
98              request.getSession().setAttribute(UifParameters.FORM_MANAGER, uifFormManager);
99          }
100 
101         // add form manager to GlobalVariables for easy reference by other controller methods
102         GlobalVariables.setUifFormManager(uifFormManager);
103 
104         String formKeyParam = request.getParameter(UifParameters.FORM_KEY);
105         if (StringUtils.isNotBlank(formKeyParam)) {
106             form = uifFormManager.getForm(formKeyParam);
107         } else {
108             form = createInitialForm(request);
109         }
110 
111         uifFormManager.setCurrentForm(form);
112 
113         return form;
114     }
115 
116     /**
117      * Called to create a new model(form) object when necessary. This usually occurs on the initial request
118      * in a conversation (when the model is not present in the session). This method must be
119      * overridden when extending a controller and using a different form type than the superclass.
120      *
121      * @param request - the http request that was made
122      */
123     protected abstract UifFormBase createInitialForm(HttpServletRequest request);
124 
125     /**
126      * Initial method called when requesting a new view instance which checks authorization and forwards
127      * the view for rendering
128      */
129     @RequestMapping(params = "methodToCall=start")
130     public ModelAndView start(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
131             HttpServletRequest request, HttpServletResponse response) {
132 
133         // check view authorization
134         // TODO: this needs to be invoked for each request
135         if (form.getView() != null) {
136             String methodToCall = request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER);
137             checkViewAuthorization(form, methodToCall);
138         }
139 
140         return getUIFModelAndView(form);
141     }
142 
143     /**
144      * Invokes the configured {@link org.kuali.rice.krad.uif.view.ViewAuthorizer} to verify the user has access to
145      * open the view. An exception is thrown if access has not been granted
146      *
147      * <p>
148      * Note this method is invoked automatically by the controller interceptor for each request
149      * </p>
150      *
151      * @param form - form instance containing the request data
152      * @param methodToCall - the request parameter 'methodToCall' which is used to determine the controller
153      * method invoked
154      */
155     public void checkViewAuthorization(UifFormBase form, String methodToCall) throws AuthorizationException {
156         Person user = GlobalVariables.getUserSession().getPerson();
157 
158         boolean canOpenView = form.getView().getAuthorizer().canOpenView(form.getView(), form, user);
159         if (!canOpenView) {
160             throw new AuthorizationException(user.getPrincipalName(), "open", form.getView().getId(),
161                     "User '" + user.getPrincipalName() + "' is not authorized to open view ID: " + form.getView()
162                             .getId(), null);
163         }
164     }
165 
166     /**
167      * Called by the add line action for a new collection line. Method
168      * determines which collection the add action was selected for and invokes
169      * the view helper service to add the line
170      */
171     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=addLine")
172     public ModelAndView addLine(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
173             HttpServletRequest request, HttpServletResponse response) {
174 
175         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
176         if (StringUtils.isBlank(selectedCollectionPath)) {
177             throw new RuntimeException("Selected collection was not set for add line action, cannot add new line");
178         }
179 
180         View view = uifForm.getPreviousView();
181         view.getViewHelperService().processCollectionAddLine(view, uifForm, selectedCollectionPath);
182 
183         return updateComponent(uifForm, result, request, response);
184     }
185 
186     /**
187      * Called by the delete line action for a model collection. Method
188      * determines which collection the action was selected for and the line
189      * index that should be removed, then invokes the view helper service to
190      * process the action
191      */
192     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=deleteLine")
193     public ModelAndView deleteLine(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
194             HttpServletRequest request, HttpServletResponse response) {
195 
196         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
197         if (StringUtils.isBlank(selectedCollectionPath)) {
198             throw new RuntimeException("Selected collection was not set for delete line action, cannot delete line");
199         }
200 
201         int selectedLineIndex = -1;
202         String selectedLine = uifForm.getActionParamaterValue(UifParameters.SELECTED_LINE_INDEX);
203         if (StringUtils.isNotBlank(selectedLine)) {
204             selectedLineIndex = Integer.parseInt(selectedLine);
205         }
206 
207         if (selectedLineIndex == -1) {
208             throw new RuntimeException("Selected line index was not set for delete line action, cannot delete line");
209         }
210 
211         View view = uifForm.getPreviousView();
212         view.getViewHelperService().processCollectionDeleteLine(view, uifForm, selectedCollectionPath,
213                 selectedLineIndex);
214 
215         return updateComponent(uifForm, result, request, response);
216     }
217 
218     /**
219      * Invoked to toggle the show inactive indicator on the selected collection group and then
220      * rerun the component lifecycle and rendering based on the updated indicator and form data
221      *
222      * @param request - request object that should contain the request component id (for the collection group)
223      * and the show inactive indicator value
224      */
225     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=toggleInactiveRecordDisplay")
226     public ModelAndView toggleInactiveRecordDisplay(@ModelAttribute("KualiForm") UifFormBase uifForm,
227             BindingResult result, HttpServletRequest request, HttpServletResponse response) {
228         String collectionGroupId = request.getParameter(UifParameters.REQUESTED_COMPONENT_ID);
229         if (StringUtils.isBlank(collectionGroupId)) {
230             throw new RuntimeException(
231                     "Collection group id to update for inactive record display not found in request");
232         }
233 
234         String showInactiveStr = request.getParameter(UifParameters.SHOW_INACTIVE_RECORDS);
235         Boolean showInactive = false;
236         if (StringUtils.isNotBlank(showInactiveStr)) {
237             // TODO: should use property editors once we have util class
238             showInactive = (Boolean) (new BooleanFormatter()).convertFromPresentationFormat(showInactiveStr);
239         } else {
240             throw new RuntimeException("Show inactive records flag not found in request");
241         }
242 
243         CollectionGroup collectionGroup = (CollectionGroup) ComponentFactory.getNewInstanceForRefresh(uifForm.getView(),
244                 collectionGroupId);
245 
246         // update inactive flag on group
247         collectionGroup.setShowInactive(showInactive);
248 
249         // run lifecycle and update in view
250         uifForm.getView().getViewHelperService().performComponentLifecycle(uifForm.getView(), uifForm, collectionGroup,
251                 collectionGroupId);
252 
253         return UifWebUtils.getComponentModelAndView(collectionGroup, uifForm);
254     }
255 
256     /**
257      * Just returns as if return with no value was selected.
258      */
259     @RequestMapping(params = "methodToCall=cancel")
260     public ModelAndView cancel(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
261             HttpServletRequest request, HttpServletResponse response) {
262         return close(form, result, request, response);
263     }
264 
265     /**
266      * Just returns as if return with no value was selected.
267      */
268     @RequestMapping(params = "methodToCall=close")
269     public ModelAndView close(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
270             HttpServletRequest request, HttpServletResponse response) {
271         Properties props = new Properties();
272         props.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.REFRESH);
273         if (StringUtils.isNotBlank(form.getReturnFormKey())) {
274             props.put(UifParameters.FORM_KEY, form.getReturnFormKey());
275         }
276 
277         // TODO this needs setup for lightbox and possible home location
278         // property
279         String returnUrl = form.getReturnLocation();
280         if (StringUtils.isBlank(returnUrl)) {
281             returnUrl = ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.APPLICATION_URL_KEY);
282         }
283 
284         return performRedirect(form, returnUrl, props);
285     }
286 
287     /**
288      * Invoked to navigate back one page in history..
289      *
290      * @param form - form object that should contain the history object
291      */
292     @RequestMapping(params = "methodToCall=returnToPrevious")
293     public ModelAndView returnToPrevious(@ModelAttribute("KualiForm") UifFormBase form) {
294 
295         return returnToHistory(form, false);
296     }
297 
298     /**
299      * Invoked to navigate back to the first page in history.
300      *
301      * @param form - form object that should contain the history object
302      */
303     @RequestMapping(params = "methodToCall=returnToHub")
304     public ModelAndView returnToHub(@ModelAttribute("KualiForm") UifFormBase form) {
305 
306         return returnToHistory(form, true);
307     }
308 
309     /**
310      * Invoked to navigate back to a history entry. The homeFlag will determine whether navigation
311      * will be back to the first or last history entry.
312      *
313      * @param form - form object that should contain the history object
314      * @param homeFlag - if true will navigate back to first entry else will navigate to last entry
315      * in the history
316      */
317     public ModelAndView returnToHistory(UifFormBase form, boolean homeFlag) {
318         // Get the history from the form
319         History hist = form.getFormHistory();
320         List<HistoryEntry> histEntries = hist.getHistoryEntries();
321 
322         // Get the history page url. Default to the application url if there is no history.
323         String histUrl = null;
324         if (histEntries.isEmpty()) {
325             histUrl = ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.APPLICATION_URL_KEY);
326         } else {
327             // For home get the first entry, for previous get the last entry.
328             // Remove history up to where page is opened
329             if (homeFlag) {
330                 histUrl = histEntries.get(0).getUrl();
331                 histEntries.clear();
332             } else {
333                 histUrl = histEntries.get(histEntries.size() - 1).getUrl();
334                 histEntries.remove(histEntries.size() - 1);
335                 hist.setCurrent(null);
336             }
337         }
338 
339         // Add the refresh call
340         Properties props = new Properties();
341         props.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.REFRESH);
342 
343         return performRedirect(form, histUrl, props);
344     }
345 
346     /**
347      * Handles menu navigation between view pages
348      */
349     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=navigate")
350     public ModelAndView navigate(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
351             HttpServletRequest request, HttpServletResponse response) {
352         String pageId = form.getActionParamaterValue(UifParameters.NAVIGATE_TO_PAGE_ID);
353 
354         // only refreshing page
355         form.setRenderFullView(false);
356 
357         return getUIFModelAndView(form, pageId);
358     }
359 
360     @RequestMapping(params = "methodToCall=refresh")
361     public ModelAndView refresh(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
362             HttpServletRequest request, HttpServletResponse response) throws Exception {
363         // TODO: this code still needs to handle reference refreshes
364         String refreshCallerType = "";
365         if (request.getParameterMap().containsKey(KRADConstants.REFRESH_CALLER_TYPE)) {
366             refreshCallerType = request.getParameter(KRADConstants.REFRESH_CALLER_TYPE);
367         }
368 
369         // process multi-value lookup returns
370         if (StringUtils.equals(refreshCallerType, UifConstants.RefreshCallerTypes.MULTI_VALUE_LOOKUP)) {
371             String lookupCollectionName = "";
372             if (request.getParameterMap().containsKey(UifParameters.LOOKUP_COLLECTION_NAME)) {
373                 lookupCollectionName = request.getParameter(UifParameters.LOOKUP_COLLECTION_NAME);
374             }
375 
376             if (StringUtils.isBlank(lookupCollectionName)) {
377                 throw new RuntimeException(
378                         "Lookup collection name is required for processing multi-value lookup results");
379             }
380 
381             String selectedLineValues = "";
382             if (request.getParameterMap().containsKey(UifParameters.SELECTED_LINE_VALUES)) {
383                 selectedLineValues = request.getParameter(UifParameters.SELECTED_LINE_VALUES);
384             }
385 
386             // invoked view helper to populate the collection from lookup results
387             form.getPreviousView().getViewHelperService().processMultipleValueLookupResults(form.getPreviousView(),
388                     form, lookupCollectionName, selectedLineValues);
389         }
390 
391         form.setRenderFullView(true);
392 
393         return getUIFModelAndView(form);
394     }
395 
396     /**
397      * Updates the current component by retrieving a fresh copy from the dictionary,
398      * running its component lifecycle, and returning it
399      *
400      * @param request - the request must contain reqComponentId that specifies the component to retrieve
401      */
402     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=updateComponent")
403     public ModelAndView updateComponent(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
404             HttpServletRequest request, HttpServletResponse response) {
405         String requestedComponentId = request.getParameter(UifParameters.REQUESTED_COMPONENT_ID);
406         if (StringUtils.isBlank(requestedComponentId)) {
407             throw new RuntimeException("Requested component id for update not found in request");
408         }
409 
410         // get a new instance of the component
411         Component comp = ComponentFactory.getNewInstanceForRefresh(form.getView(), requestedComponentId);
412 
413         // run lifecycle and update in view
414         form.getView().getViewHelperService().performComponentLifecycle(form.getView(), form, comp,
415                 requestedComponentId);
416 
417         //Regenerate server message content for page
418         form.getView().getCurrentPage().getErrorsField().setDisplayNestedMessages(true);
419         form.getView().getCurrentPage().getErrorsField().generateMessages(false, form.getView(),
420                 form,form.getView().getCurrentPage());
421 
422         return UifWebUtils.getComponentModelAndView(comp, form);
423     }
424 
425     /**
426      * Builds up a URL to the lookup view based on the given post action
427      * parameters and redirects
428      */
429     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=performLookup")
430     public ModelAndView performLookup(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
431             HttpServletRequest request, HttpServletResponse response) {
432         Properties lookupParameters = form.getActionParametersAsProperties();
433 
434         String lookupObjectClassName = (String) lookupParameters.get(UifParameters.DATA_OBJECT_CLASS_NAME);
435         Class<?> lookupObjectClass = null;
436         try {
437             lookupObjectClass = Class.forName(lookupObjectClassName);
438         } catch (ClassNotFoundException e) {
439             LOG.error("Unable to get class for name: " + lookupObjectClassName);
440             throw new RuntimeException("Unable to get class for name: " + lookupObjectClassName, e);
441         }
442 
443         // get form values for the lookup parameter fields
444         String lookupParameterString = (String) lookupParameters.get(UifParameters.LOOKUP_PARAMETERS);
445         if (lookupParameterString != null) {
446             Map<String, String> lookupParameterFields = KRADUtils.getMapFromParameterString(lookupParameterString);
447             for (Entry<String, String> lookupParameter : lookupParameterFields.entrySet()) {
448                 String lookupParameterValue = LookupInquiryUtils.retrieveLookupParameterValue(form, request,
449                         lookupObjectClass, lookupParameter.getValue(), lookupParameter.getKey());
450 
451                 if (StringUtils.isNotBlank(lookupParameterValue)) {
452                     lookupParameters.put(UifPropertyPaths.CRITERIA_FIELDS + "['" + lookupParameter.getValue() + "']",
453                             lookupParameterValue);
454                 }
455             }
456         }
457 
458         // TODO: lookup anchors and doc number?
459 
460         String baseLookupUrl = (String) lookupParameters.get(UifParameters.BASE_LOOKUP_URL);
461         lookupParameters.remove(UifParameters.BASE_LOOKUP_URL);
462 
463         // set lookup method to call
464         lookupParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.START);
465         String autoSearchString = (String) lookupParameters.get(UifParameters.AUTO_SEARCH);
466         if (Boolean.parseBoolean(autoSearchString)) {
467             lookupParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.SEARCH);
468         }
469 
470         lookupParameters.put(UifParameters.RETURN_LOCATION, form.getFormPostUrl());
471         lookupParameters.put(UifParameters.RETURN_FORM_KEY, form.getFormKey());
472 
473         // special check for external object classes
474         if (lookupObjectClass != null) {
475             ModuleService responsibleModuleService =
476                     KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(lookupObjectClass);
477             if (responsibleModuleService != null && responsibleModuleService.isExternalizable(lookupObjectClass)) {
478                 String lookupUrl = responsibleModuleService.getExternalizableDataObjectLookupUrl(lookupObjectClass,
479                         lookupParameters);
480 
481                 Properties externalInquiryProperties = new Properties();
482                 if (lookupParameters.containsKey(UifParameters.LIGHTBOX_CALL)) {
483                     externalInquiryProperties.put(UifParameters.LIGHTBOX_CALL, lookupParameters.get(
484                             UifParameters.LIGHTBOX_CALL));
485                 }
486 
487                 return performRedirect(form, lookupUrl, externalInquiryProperties);
488             }
489         }
490 
491         return performRedirect(form, baseLookupUrl, lookupParameters);
492     }
493 
494     /**
495      * Invoked to provide the options for a suggest widget. The valid options are retrieved by the associated
496      * <code>AttributeQuery</code> for the field containing the suggest widget. The controller method picks
497      * out the query parameters from the request and calls <code>AttributeQueryService</code> to perform the
498      * suggest query and prepare the result object that will be exposed with JSON
499      */
500     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=performFieldSuggest")
501     public
502     @ResponseBody
503     AttributeQueryResult performFieldSuggest(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
504             HttpServletRequest request, HttpServletResponse response) {
505 
506         // retrieve query fields from request
507         Map<String, String> queryParameters = new HashMap<String, String>();
508         for (Object parameterName : request.getParameterMap().keySet()) {
509             if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETER + ".")) {
510                 String fieldName = StringUtils.substringAfter(parameterName.toString(),
511                         UifParameters.QUERY_PARAMETER + ".");
512                 String fieldValue = request.getParameter(parameterName.toString());
513                 queryParameters.put(fieldName, fieldValue);
514             }
515         }
516 
517         // retrieve id for field to perform query for
518         String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID);
519         if (StringUtils.isBlank(queryFieldId)) {
520             throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: "
521                     + UifParameters.QUERY_FIELD_ID);
522         }
523 
524         // get the field term to match
525         String queryTerm = request.getParameter(UifParameters.QUERY_TERM);
526         if (StringUtils.isBlank(queryTerm)) {
527             throw new RuntimeException(
528                     "Unable to find id for query term value for attribute query on under request parameter name: "
529                             + UifParameters.QUERY_TERM);
530         }
531 
532         // invoke attribute query service to perform the query
533         AttributeQueryResult queryResult = KRADServiceLocatorWeb.getAttributeQueryService().performFieldSuggestQuery(
534                 form.getView(), queryFieldId, queryTerm, queryParameters);
535 
536         return queryResult;
537     }
538 
539     /**
540      * Invoked to execute the <code>AttributeQuery</code> associated with a field given the query parameters
541      * found in the request. This controller method picks out the query parameters from the request and calls
542      * <code>AttributeQueryService</code> to perform the field query and prepare the result object
543      * that will be exposed with JSON. The result is then used to update field values in the UI with client
544      * script.
545      */
546     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=performFieldQuery")
547     public
548     @ResponseBody
549     AttributeQueryResult performFieldQuery(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
550             HttpServletRequest request, HttpServletResponse response) {
551 
552         // retrieve query fields from request
553         Map<String, String> queryParameters = new HashMap<String, String>();
554         for (Object parameterName : request.getParameterMap().keySet()) {
555             if (parameterName.toString().startsWith(UifParameters.QUERY_PARAMETER + ".")) {
556                 String fieldName = StringUtils.substringAfter(parameterName.toString(),
557                         UifParameters.QUERY_PARAMETER + ".");
558                 String fieldValue = request.getParameter(parameterName.toString());
559                 queryParameters.put(fieldName, fieldValue);
560             }
561         }
562 
563         // retrieve id for field to perform query for
564         String queryFieldId = request.getParameter(UifParameters.QUERY_FIELD_ID);
565         if (StringUtils.isBlank(queryFieldId)) {
566             throw new RuntimeException("Unable to find id for field to perform query on under request parameter name: "
567                     + UifParameters.QUERY_FIELD_ID);
568         }
569 
570         // invoke attribute query service to perform the query
571         AttributeQueryResult queryResult = KRADServiceLocatorWeb.getAttributeQueryService().performFieldQuery(
572                 form.getView(), queryFieldId, queryParameters);
573 
574         return queryResult;
575     }
576 
577     /**
578      * Builds a <code>ModelAndView</code> instance configured to redirect to the
579      * URL formed by joining the base URL with the given URL parameters
580      *
581      * @param form - current form instance
582      * @param baseUrl - base url to redirect to
583      * @param urlParameters - properties containing key/value pairs for the url parameters, if null or empty,
584      * the baseUrl will be used as the full URL
585      * @return ModelAndView configured to redirect to the given URL
586      */
587     protected ModelAndView performRedirect(UifFormBase form, String baseUrl, Properties urlParameters) {
588         // since we are redirecting and will not be rendering the view, we need to reset the view from the previous
589         form.setView(form.getPreviousView());
590 
591         // clear current form from session
592         GlobalVariables.getUifFormManager().removeForm(form);
593 
594         // On post redirects we need to make sure we are sending the history forward:
595         urlParameters.setProperty(UifConstants.UrlParams.HISTORY, form.getFormHistory().getHistoryParameterString());
596 
597         // If this is an Light Box call only return the redirectURL view with the URL
598         // set this is to avoid automatic redirect when using light boxes
599         if (urlParameters.get(UifParameters.LIGHTBOX_CALL) != null &&
600                 urlParameters.get(UifParameters.LIGHTBOX_CALL).equals("true")) {
601             urlParameters.remove(UifParameters.LIGHTBOX_CALL);
602             String redirectUrl = UrlFactory.parameterizeUrl(baseUrl, urlParameters);
603 
604             ModelAndView modelAndView = new ModelAndView(UifConstants.SPRING_REDIRECT_ID);
605             modelAndView.addObject("redirectUrl", redirectUrl);
606             return modelAndView;
607         }
608 
609         String redirectUrl = UrlFactory.parameterizeUrl(baseUrl, urlParameters);
610         ModelAndView modelAndView = new ModelAndView(REDIRECT_PREFIX + redirectUrl);
611 
612         return modelAndView;
613     }
614 
615     protected ModelAndView getUIFModelAndView(UifFormBase form) {
616         return getUIFModelAndView(form, form.getPageId());
617     }
618 
619     /**
620      * Configures the <code>ModelAndView</code> instance containing the form
621      * data and pointing to the UIF generic spring view
622      *
623      * @param form - Form instance containing the model data
624      * @param pageId - Id of the page within the view that should be rendered, can
625      * be left blank in which the current or default page is rendered
626      * @return ModelAndView object with the contained form
627      */
628     protected ModelAndView getUIFModelAndView(UifFormBase form, String pageId) {
629         return UifWebUtils.getUIFModelAndView(form, pageId);
630     }
631 
632     protected ViewService getViewService() {
633         return KRADServiceLocatorWeb.getViewService();
634     }
635 
636     public SessionDocumentService getSessionDocumentService() {
637         return KRADServiceLocatorWeb.getSessionDocumentService();
638     }
639 
640 }