View Javadoc
1   /**
2    * Copyright 2005-2014 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.form;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Properties;
25  import java.util.Set;
26  import java.util.UUID;
27  
28  import javax.servlet.http.HttpServletRequest;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.codehaus.jackson.map.ObjectMapper;
32  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33  import org.kuali.rice.krad.uif.UifConstants;
34  import org.kuali.rice.krad.uif.UifConstants.ViewType;
35  import org.kuali.rice.krad.uif.UifParameters;
36  import org.kuali.rice.krad.uif.UifPropertyPaths;
37  import org.kuali.rice.krad.uif.component.Component;
38  import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
39  import org.kuali.rice.krad.uif.service.ViewHelperService;
40  import org.kuali.rice.krad.uif.service.ViewService;
41  import org.kuali.rice.krad.uif.util.SessionTransient;
42  import org.kuali.rice.krad.uif.view.View;
43  import org.kuali.rice.krad.uif.view.ViewModel;
44  import org.kuali.rice.krad.util.KRADUtils;
45  import org.kuali.rice.krad.web.bind.RequestAccessible;
46  import org.springframework.web.multipart.MultipartFile;
47  
48  /**
49   * Base form class for views within the KRAD User Interface Framework.
50   *
51   * <p>Holds properties necessary to determine the {@link org.kuali.rice.krad.uif.view.View} instance that
52   * will be used to render the user interface</p>
53   *
54   * @author Kuali Rice Team (rice.collab@kuali.org)
55   */
56  public class UifFormBase implements ViewModel {
57      private static final long serialVersionUID = 8432543267099454434L;
58  
59      @RequestAccessible
60      protected String viewId;
61  
62      @RequestAccessible
63      protected String viewName;
64  
65      @RequestAccessible
66      protected ViewType viewTypeName;
67  
68      @RequestAccessible
69      protected String pageId;
70  
71      @RequestAccessible
72      protected String methodToCall;
73  
74      @RequestAccessible
75      protected String formKey;
76  
77      @RequestAccessible
78      @SessionTransient
79      protected String requestedFormKey;
80  
81      @RequestAccessible
82      protected String flowKey;
83  
84      protected String sessionId;
85      protected int sessionTimeoutInterval;
86  
87      @SessionTransient
88      protected HistoryFlow historyFlow;
89      @SessionTransient
90      protected HistoryManager historyManager;
91  
92      @RequestAccessible
93      @SessionTransient
94      protected String jumpToId;
95  
96      @SessionTransient
97      protected String jumpToName;
98  
99      @RequestAccessible
100     @SessionTransient
101     protected String focusId;
102 
103     @RequestAccessible
104     @SessionTransient
105     protected boolean dirtyForm;
106 
107     protected String formPostUrl;
108     protected String controllerMapping;
109 
110     @SessionTransient
111     private String requestUrl;
112     private Map<String, String[]> initialRequestParameters;
113 
114     protected String state;
115     protected List<String> viewsThatNeedDefaultValuesApplied;
116 
117     @RequestAccessible
118     protected boolean renderedInLightBox;
119 
120     @RequestAccessible
121     protected boolean renderedInIframe;
122 
123     @SessionTransient
124     protected String growlScript;
125 
126     @SessionTransient
127     protected View view;
128     protected ViewPostMetadata viewPostMetadata;
129 
130     protected Map<String, String> viewRequestParameters;
131     protected List<String> readOnlyFieldsList;
132 
133     protected Map<String, Object> newCollectionLines;
134 
135     @RequestAccessible
136     @SessionTransient
137     protected String triggerActionId;
138 
139     @RequestAccessible
140     @SessionTransient
141     protected Map<String, String> actionParameters;
142 
143     protected Map<String, Object> clientStateForSyncing;
144 
145     @SessionTransient
146     protected Map<String, Set<String>> selectedCollectionLines;
147 
148     protected Set<String> selectedLookupResultsCache;
149 
150     protected List<Object> addedCollectionItems;
151 
152     @SessionTransient
153     protected MultipartFile attachmentFile;
154 
155     // navigation
156     @RequestAccessible
157     protected String returnLocation;
158 
159     @RequestAccessible
160     protected String returnFormKey;
161 
162     @RequestAccessible
163     @SessionTransient
164     protected boolean ajaxRequest;
165 
166     @RequestAccessible
167     @SessionTransient
168     protected String ajaxReturnType;
169 
170     @SessionTransient
171     private String requestJsonTemplate;
172     @SessionTransient
173     private boolean collectionPagingRequest;
174 
175     // dialog fields
176     @RequestAccessible
177     @SessionTransient
178     protected String returnDialogId;
179 
180     @SessionTransient
181     protected String returnDialogResponse;
182 
183     protected Map<String, String> dialogExplanations;
184     protected Map<String, DialogResponse> dialogResponses;
185 
186     @SessionTransient
187     protected boolean requestRedirected;
188 
189     @RequestAccessible
190     @SessionTransient
191     protected String updateComponentId;
192     @SessionTransient
193     private Component updateComponent;
194 
195     @RequestAccessible
196     protected Map<String, Object> extensionData;
197 
198     protected Map<String, String> queryParameters;
199 
200     public UifFormBase() {
201         renderedInLightBox = false;
202         renderedInIframe = false;
203         requestRedirected = false;
204 
205         readOnlyFieldsList = new ArrayList<String>();
206         viewRequestParameters = new HashMap<String, String>();
207         newCollectionLines = new HashMap<String, Object>();
208         actionParameters = new HashMap<String, String>();
209         clientStateForSyncing = new HashMap<String, Object>();
210         selectedCollectionLines = new HashMap<String, Set<String>>();
211         selectedLookupResultsCache = new HashSet<String>();
212         addedCollectionItems = new ArrayList<Object>();
213         dialogExplanations = new HashMap<String, String>();
214         dialogResponses = new HashMap<String,DialogResponse>();
215         extensionData = new HashMap<String, Object>();
216         queryParameters = new HashMap<String, String>();
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     public void preBind(HttpServletRequest request) {
224         // do nothing - here for framework
225     }
226 
227     /**
228      * {@inheritDoc}
229      */
230     @Override
231     public void postBind(HttpServletRequest request) {
232         // assign form key if this is a new form or the requested form key is not in session
233         UifFormManager uifFormManager = (UifFormManager) request.getSession().getAttribute(UifParameters.FORM_MANAGER);
234         if (StringUtils.isBlank(formKey) || !uifFormManager.hasSessionForm(formKey)) {
235             formKey = generateFormKey();
236         }
237 
238         // default form post URL to request URL
239         formPostUrl = request.getRequestURL().toString();
240 
241         if (request.getSession() != null) {
242             sessionId = request.getSession().getId();
243             sessionTimeoutInterval = request.getSession().getMaxInactiveInterval();
244         }
245 
246         //set controller mapping property
247         controllerMapping = request.getPathInfo();
248 
249         // get any sent client view state and parse into map
250         if (request.getParameterMap().containsKey(UifParameters.CLIENT_VIEW_STATE)) {
251             String clientStateJSON = request.getParameter(UifParameters.CLIENT_VIEW_STATE);
252             if (StringUtils.isNotBlank(clientStateJSON)) {
253                 // change single quotes to double quotes (necessary because the reverse was done for sending)
254                 clientStateJSON = StringUtils.replace(clientStateJSON, "\\'", "\"");
255                 clientStateJSON = StringUtils.replace(clientStateJSON, "\\[", "[");
256                 clientStateJSON = StringUtils.replace(clientStateJSON, "\\]", "]");
257                 clientStateJSON = StringUtils.replace(clientStateJSON, "'",  "\"");
258 
259                 ObjectMapper mapper = new ObjectMapper();
260                 try {
261                     clientStateForSyncing = mapper.readValue(clientStateJSON, Map.class);
262                 } catch (IOException e) {
263                     throw new RuntimeException("Unable to decode client side state JSON: " + clientStateJSON, e);
264                 }
265             }
266         }
267 
268         // populate read only fields list
269         if (request.getParameter(UifParameters.READ_ONLY_FIELDS) != null) {
270             String readOnlyFields = request.getParameter(UifParameters.READ_ONLY_FIELDS);
271             setReadOnlyFieldsList(KRADUtils.convertStringParameterToList(readOnlyFields));
272         }
273 
274         // collect dialog response, or initialize new map of responses
275         if (request.getParameter(UifParameters.RETURN_FROM_DIALOG) != null) {
276             String dialogExplanation = null;
277             if ((dialogExplanations != null) && dialogExplanations.containsKey(returnDialogId)) {
278                 dialogExplanation = dialogExplanations.get(returnDialogId);
279             }
280 
281             DialogResponse response = new DialogResponse(returnDialogId, returnDialogResponse, dialogExplanation);
282             this.dialogResponses.put(this.returnDialogId, response);
283         } else {
284             this.dialogResponses = new HashMap<String, DialogResponse>();
285         }
286 
287         // clean parameters from XSS attacks that will be written out as hiddens
288         this.pageId = KRADUtils.stripXSSPatterns(this.pageId);
289         this.methodToCall = KRADUtils.stripXSSPatterns(this.methodToCall);
290         this.formKey = KRADUtils.stripXSSPatterns(this.formKey);
291         this.requestedFormKey = KRADUtils.stripXSSPatterns(this.requestedFormKey);
292         this.flowKey = KRADUtils.stripXSSPatterns(this.flowKey);
293         this.sessionId = KRADUtils.stripXSSPatterns(this.sessionId);
294         this.formPostUrl = KRADUtils.stripXSSPatterns(this.formPostUrl);
295         this.returnLocation = KRADUtils.stripXSSPatterns(this.returnLocation);
296         this.returnFormKey = KRADUtils.stripXSSPatterns(this.returnFormKey);
297         this.requestUrl = KRADUtils.stripXSSPatterns(this.requestUrl);
298     }
299 
300     /**
301      * {@inheritDoc}
302      */
303     @Override
304     public void preRender(HttpServletRequest request) {
305         // clear dialog properties so previous values do not appear for new dialogs
306         this.returnDialogId = null;
307         this.returnDialogResponse = null;
308         this.dialogExplanations = new HashMap<String, String>();
309     }
310 
311     /**
312      * Creates the unique id used to store this "conversation" in the session.
313      * The default method generates a java UUID.
314      *
315      * @return UUID
316      */
317     protected String generateFormKey() {
318         return UUID.randomUUID().toString();
319     }
320 
321     /**
322      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewId()
323      */
324     @Override
325     public String getViewId() {
326         return this.viewId;
327     }
328 
329     /**
330      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewId(String)
331      */
332     @Override
333     public void setViewId(String viewId) {
334         this.viewId = viewId;
335     }
336 
337     /**
338      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewName()
339      */
340     @Override
341     public String getViewName() {
342         return this.viewName;
343     }
344 
345     /**
346      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewName(String)
347      */
348     @Override
349     public void setViewName(String viewName) {
350         this.viewName = viewName;
351     }
352 
353     /**
354      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewTypeName()
355      */
356     @Override
357     public ViewType getViewTypeName() {
358         return this.viewTypeName;
359     }
360 
361     /**
362      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewTypeName(org.kuali.rice.krad.uif.UifConstants.ViewType)
363      */
364     @Override
365     public void setViewTypeName(ViewType viewTypeName) {
366         this.viewTypeName = viewTypeName;
367     }
368 
369     /**
370      * @see org.kuali.rice.krad.uif.view.ViewModel#getPageId()
371      */
372     @Override
373     public String getPageId() {
374         return this.pageId;
375     }
376 
377     /**
378      * @see org.kuali.rice.krad.uif.view.ViewModel#setPageId(String)
379      */
380     @Override
381     public void setPageId(String pageId) {
382         this.pageId = pageId;
383     }
384 
385     /**
386      * @see org.kuali.rice.krad.uif.view.ViewModel#getFormPostUrl()
387      */
388     @Override
389     public String getFormPostUrl() {
390         return this.formPostUrl;
391     }
392 
393     /**
394      * @see org.kuali.rice.krad.uif.view.ViewModel#setFormPostUrl(String)
395      */
396     @Override
397     public void setFormPostUrl(String formPostUrl) {
398         this.formPostUrl = formPostUrl;
399     }
400 
401     /**
402      * Name of the controllerMapping for this form (includes slash)
403      *
404      * @return the controllerMapping string
405      */
406     public String getControllerMapping() {
407         return controllerMapping;
408     }
409 
410     /**
411      * The current {@link HistoryFlow} for this form which stores a trail of urls/breadcrumbs primarily used for
412      * path-based breadcrumb display
413      *
414      * @return the {@link HistoryFlow}
415      */
416     public HistoryFlow getHistoryFlow() {
417         return historyFlow;
418     }
419 
420     /**
421      * Set the current HistoryFlow for this form
422      *
423      * @param historyFlow
424      */
425     public void setHistoryFlow(HistoryFlow historyFlow) {
426         this.historyFlow = historyFlow;
427     }
428 
429     /**
430      * The current {@link HistoryManager} that was pulled from session which store all {@link HistoryFlow} objects in
431      * the current session to keep track of the path the user has taken across views (primarily used by path-based
432      * breadcrumbs)
433      *
434      * @return the HistoryManager
435      */
436     public HistoryManager getHistoryManager() {
437         return historyManager;
438     }
439 
440     /**
441      * Set the current HistoryManager
442      *
443      * @param historyManager
444      */
445     public void setHistoryManager(HistoryManager historyManager) {
446         this.historyManager = historyManager;
447     }
448 
449     /**
450      * The flowKey representing the HistoryFlow this form may be in.
451      *
452      * <p>This allows for a flow to continue by key or start (if set to "start").
453      * If null or blank, no flow (or path based
454      * breadcrumbs) are being tracked.</p>
455      *
456      * @return the flowKey
457      */
458     public String getFlowKey() {
459         return flowKey;
460     }
461 
462     /**
463      * Set the flowKey
464      *
465      * @param flowKey
466      */
467     public void setFlowKey(String flowKey) {
468         this.flowKey = flowKey;
469     }
470 
471     /**
472      * The original requestUrl for the View represented by this form (url received by the controller for initial
473      * request)
474      *
475      * @return the requestUrl
476      */
477     public String getRequestUrl() {
478         return requestUrl;
479     }
480 
481     /**
482      * Set the requestUrl
483      *
484      * @param requestUrl
485      */
486     public void setRequestUrl(String requestUrl) {
487         this.requestUrl = requestUrl;
488     }
489 
490     /**
491      * The requestParameters represent all the parameters in the query string that were initially passed to this View
492      * by the initial request
493      *
494      * @return the requestParameters
495      */
496     public Map<String, String[]> getInitialRequestParameters() {
497         return initialRequestParameters;
498     }
499 
500     /**
501      * Set the requestParameters
502      *
503      * @param requestParameters
504      */
505     public void setInitialRequestParameters(Map<String, String[]> requestParameters) {
506         this.initialRequestParameters = requestParameters;
507     }
508 
509     public String getReturnLocation() {
510         return this.returnLocation;
511     }
512 
513     public void setReturnLocation(String returnLocation) {
514         this.returnLocation = returnLocation;
515     }
516 
517     public String getReturnFormKey() {
518         return this.returnFormKey;
519     }
520 
521     public void setReturnFormKey(String returnFormKey) {
522         this.returnFormKey = returnFormKey;
523     }
524 
525     /**
526      * Holds the id for the user's current session
527      *
528      * <p>
529      * The user's session id is used to track when a timeout has occurred and enforce the policy
530      * configured with the {@link org.kuali.rice.krad.uif.view.ViewSessionPolicy}. This property gets initialized
531      * in the {@link #postBind(javax.servlet.http.HttpServletRequest)} method and then is written out as a
532      * hidden on the view. Therefore each post done on the view will send back the session id when the view was
533      * rendering, and the {@link org.kuali.rice.krad.web.filter.UifSessionTimeoutFilter} can use that to determine
534      * if a timeout has occurred
535      * </p>
536      *
537      * @return id for the user's current session
538      */
539     public String getSessionId() {
540         return sessionId;
541     }
542 
543     /**
544      * Holds the configured session timeout interval
545      *
546      * <p>
547      * Holds the session timeout interval so it can be referenced to give the user notifications (for example the
548      * session timeout warning reads this property). This is initialized from the session object in
549      * {@link #postBind(javax.servlet.http.HttpServletRequest)}
550      * </p>
551      *
552      * @return amount of time in milliseconds before the session will timeout
553      */
554     public int getSessionTimeoutInterval() {
555         return sessionTimeoutInterval;
556     }
557 
558     /**
559      * Identifies the controller method that should be invoked to fulfill a
560      * request. The value will be matched up against the 'params' setting on the
561      * {@code RequestMapping} annotation for the controller method
562      *
563      * @return String method to call
564      */
565     public String getMethodToCall() {
566         return this.methodToCall;
567     }
568 
569     /**
570      * Setter for the method to call
571      *
572      * @param methodToCall
573      */
574     public void setMethodToCall(String methodToCall) {
575         this.methodToCall = methodToCall;
576     }
577 
578     /**
579      * {@inheritDoc}
580      */
581     @Override
582     public Map<String, String> getViewRequestParameters() {
583         return this.viewRequestParameters;
584     }
585 
586     /**
587      * {@inheritDoc}
588      */
589     @Override
590     public void setViewRequestParameters(Map<String, String> viewRequestParameters) {
591         this.viewRequestParameters = viewRequestParameters;
592     }
593 
594     /**
595      * {@inheritDoc}
596      */
597     @Override
598     public List<String> getReadOnlyFieldsList() {
599         return readOnlyFieldsList;
600     }
601 
602     /**
603      * {@inheritDoc}
604      */
605     @Override
606     public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) {
607         this.readOnlyFieldsList = readOnlyFieldsList;
608     }
609 
610     /**
611      * @see org.kuali.rice.krad.uif.view.ViewModel#getNewCollectionLines()
612      */
613     @Override
614     public Map<String, Object> getNewCollectionLines() {
615         return this.newCollectionLines;
616     }
617 
618     /**
619      * {@inheritDoc}
620      */
621     @Override
622     public void setNewCollectionLines(Map<String, Object> newCollectionLines) {
623         this.newCollectionLines = newCollectionLines;
624     }
625 
626     /**
627      * {@inheritDoc}
628      */
629     @Override
630     public String getTriggerActionId() {
631         return triggerActionId;
632     }
633 
634     /**
635      * {@inheritDoc}
636      */
637     @Override
638     public void setTriggerActionId(String triggerActionId) {
639         this.triggerActionId = triggerActionId;
640     }
641 
642     /**
643      * @see org.kuali.rice.krad.uif.view.ViewModel#getActionParameters()
644      */
645     @Override
646     public Map<String, String> getActionParameters() {
647         return this.actionParameters;
648     }
649 
650     /**
651      * Returns the action parameters map as a {@code Properties} instance
652      *
653      * @return Properties action parameters
654      */
655     public Properties getActionParametersAsProperties() {
656         return KRADUtils.convertMapToProperties(actionParameters);
657     }
658 
659     /**
660      * {@inheritDoc}
661      */
662     @Override
663     public void setActionParameters(Map<String, String> actionParameters) {
664         this.actionParameters = actionParameters;
665     }
666 
667     /**
668      * Retrieves the value for the given action parameter, or empty string if
669      * not found
670      *
671      * @param actionParameterName - name of the action parameter to retrieve value for
672      * @return String parameter value or empty string
673      */
674     public String getActionParamaterValue(String actionParameterName) {
675         if ((actionParameters != null) && actionParameters.containsKey(actionParameterName)) {
676             return actionParameters.get(actionParameterName);
677         }
678 
679         return "";
680     }
681 
682     /**
683      * Returns the action event that was sent in the action parameters (if any)
684      *
685      * <p>
686      * The action event is a special action parameter that can be sent to indicate a type of action being taken. This
687      * can be looked at by the view or components to render differently
688      * </p>
689      *
690      * TODO: make sure action parameters are getting reinitialized on each request
691      *
692      * @return String action event name or blank if action event was not sent
693      */
694     public String getActionEvent() {
695         if ((actionParameters != null) && actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT)) {
696             return actionParameters.get(UifConstants.UrlParams.ACTION_EVENT);
697         }
698 
699         return "";
700     }
701 
702     /**
703      * @see org.kuali.rice.krad.uif.view.ViewModel#getClientStateForSyncing()
704      */
705     @Override
706     public Map<String, Object> getClientStateForSyncing() {
707         return clientStateForSyncing;
708     }
709 
710     /**
711      * Setter for the client state
712      *
713      * @param clientStateForSyncing
714      */
715     public void setClientStateForSyncing(Map<String, Object> clientStateForSyncing) {
716         this.clientStateForSyncing = clientStateForSyncing;
717     }
718 
719     /**
720      * @see org.kuali.rice.krad.uif.view.ViewModel#getSelectedCollectionLines()
721      */
722     @Override
723     public Map<String, Set<String>> getSelectedCollectionLines() {
724         return selectedCollectionLines;
725     }
726 
727     /**
728      * {@inheritDoc}
729      */
730     @Override
731     public void setSelectedCollectionLines(Map<String, Set<String>> selectedCollectionLines) {
732         this.selectedCollectionLines = selectedCollectionLines;
733     }
734 
735     /**
736      * Holds Set of String identifiers for lines that were selected in a lookup collection results
737      * across multiple pages.
738      * The value in the cache is preserved in the session across multiple requests. This allows for the
739      * server side paging of results to retain the user choices as they move through the pages.
740      * 
741      * @return set of identifiers
742      */
743     public Set<String> getSelectedLookupResultsCache() {
744         return selectedLookupResultsCache;
745     }
746 
747     /**
748      * Sets the lookup result selection cache values
749      *
750      * @param selectedLookupResultsCache
751      */
752     public void setSelectedLookupResultsCache(Set<String> selectedLookupResultsCache) {
753         this.selectedLookupResultsCache = selectedLookupResultsCache;
754     }
755 
756     /**
757      * Key string that identifies the form instance in session storage
758      *
759      * <p>
760      * When the view is posted, the previous form instance is retrieved and then
761      * populated from the request parameters. This key string is retrieve the
762      * session form from the session service
763      * </p>
764      *
765      * @return String form session key
766      */
767     public String getFormKey() {
768         return this.formKey;
769     }
770 
771     /**
772      * Setter for the form's session key
773      *
774      * @param formKey
775      */
776     public void setFormKey(String formKey) {
777         this.formKey = formKey;
778     }
779 
780     /**
781      * This is the formKey sent on the original request.  It may differ from the actual form key stored in formKey
782      * based on if the form still exists in session by this key or not.
783      *
784      * @return the original requested form key
785      */
786     public String getRequestedFormKey() {
787         return requestedFormKey;
788     }
789 
790     /**
791      * Set the requestedFormKey
792      *
793      * @param requestedFormKey
794      */
795     public void setRequestedFormKey(String requestedFormKey) {
796         this.requestedFormKey = requestedFormKey;
797     }
798 
799     /**
800      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewsThatNeedDefaultValuesApplied()
801      */
802     @Override
803     public List<String> getViewsThatNeedDefaultValuesApplied() {
804         if(viewsThatNeedDefaultValuesApplied == null) {
805             viewsThatNeedDefaultValuesApplied = new ArrayList<String>();
806         }
807 
808         return viewsThatNeedDefaultValuesApplied;
809     }
810 
811     /**
812      * @see org.kuali.rice.krad.uif.view.ViewModel#setgetViewsThatNeedDefaultValuesApplied(List<String>)
813      */
814     @Override
815     public void setViewsThatNeedDefaultValuesApplied(List<String> viewsThatNeedDefaultValuesApplied) {
816         this.viewsThatNeedDefaultValuesApplied = viewsThatNeedDefaultValuesApplied;
817     }
818 
819     /**
820      * Adds unique view id to list of views that need default values applied.
821      *
822      * @param viewid
823      */
824     public void addViewThatNeedsDefaultValuesApplied(String viewId) {
825         if(!getViewsThatNeedDefaultValuesApplied().contains(viewId)) {
826             viewsThatNeedDefaultValuesApplied.add(viewId);
827         }
828     }
829 
830     /**
831      * Indicates whether a redirect has been requested for the view
832      *
833      * @return boolean true if redirect was requested, false if not
834      */
835     public boolean isRequestRedirected() {
836         return requestRedirected;
837     }
838 
839     /**
840      * Setter for the request redirect indicator
841      *
842      * @param requestRedirected
843      */
844     public void setRequestRedirected(boolean requestRedirected) {
845         this.requestRedirected = requestRedirected;
846     }
847 
848     /**
849      * Holder for files that are attached through the view
850      *
851      * @return MultipartFile representing the attachment
852      */
853     public MultipartFile getAttachmentFile() {
854         return this.attachmentFile;
855     }
856 
857     /**
858      * Setter for the form's attachment file
859      *
860      * @param attachmentFile
861      */
862     public void setAttachmentFile(MultipartFile attachmentFile) {
863         this.attachmentFile = attachmentFile;
864     }
865 
866     /**
867      * @see org.kuali.rice.krad.uif.view.ViewModel#getUpdateComponentId()
868      */
869     @Override
870     public String getUpdateComponentId() {
871         return updateComponentId;
872     }
873 
874     /**
875      * @see org.kuali.rice.krad.uif.view.ViewModel#setUpdateComponentId(java.lang.String)
876      */
877     @Override
878     public void setUpdateComponentId(String updateComponentId) {
879         this.updateComponentId = updateComponentId;
880     }
881 
882     /**
883      * @see org.kuali.rice.krad.uif.view.ViewModel#getUpdateComponent()
884      */
885     public Component getUpdateComponent() {
886         return updateComponent;
887     }
888 
889     /**
890      * @see org.kuali.rice.krad.uif.view.ViewModel#setUpdateComponent(org.kuali.rice.krad.uif.component.Component)
891      */
892     public void setUpdateComponent(Component updateComponent) {
893         this.updateComponent = updateComponent;
894     }
895 
896     /**
897      * @see org.kuali.rice.krad.uif.view.ViewModel#getView()
898      */
899     @Override
900     public View getView() {
901         return this.view;
902     }
903 
904     /**
905      * @see org.kuali.rice.krad.uif.view.ViewModel#setView(org.kuali.rice.krad.uif.view.View)
906      */
907     @Override
908     public void setView(View view) {
909         this.view = view;
910     }
911 
912     /**
913      * Returns an instance of the view's configured view helper service.
914      *
915      * <p>First checks if there is an initialized view containing a view helper instance. If not, and there is
916      * a view id on the form, a call is made to retrieve the view helper instance or class configuration.</p>
917      *
918      * {@inheritDoc}
919      */
920     @Override
921     public ViewHelperService getViewHelperService() {
922         if ((getView() != null) && (getView().getViewHelperService() != null)) {
923             return getView().getViewHelperService();
924         }
925 
926         String viewId = getViewId();
927         if (StringUtils.isBlank(viewId) && (getView() != null)) {
928             viewId = getView().getId();
929         }
930 
931         if (StringUtils.isBlank(viewId)) {
932             return null;
933         }
934 
935         ViewHelperService viewHelperService =
936                 (ViewHelperService) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBeanProperty(viewId,
937                         UifPropertyPaths.VIEW_HELPER_SERVICE);
938         if (viewHelperService == null) {
939             Class<?> viewHelperServiceClass =
940                     (Class<?>) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBeanProperty(viewId,
941                             UifPropertyPaths.VIEW_HELPER_SERVICE_CLASS);
942 
943             if (viewHelperServiceClass != null) {
944                 try {
945                     viewHelperService = (ViewHelperService) viewHelperServiceClass.newInstance();
946                 } catch (Exception e) {
947                     throw new RuntimeException("Unable to instantiate view helper class: " + viewHelperServiceClass, e);
948                 }
949             }
950         }
951 
952         return viewHelperService;
953     }
954 
955     /**
956      * {@inheritDoc}
957      */
958     @Override
959     public ViewPostMetadata getViewPostMetadata() {
960         return viewPostMetadata;
961     }
962 
963     /**
964      * @see UifFormBase#getViewPostMetadata()
965      */
966     @Override
967     public void setViewPostMetadata(ViewPostMetadata viewPostMetadata) {
968         this.viewPostMetadata = viewPostMetadata;
969     }
970 
971     /**
972      * Instance of the {@code ViewService} that can be used to retrieve
973      * {@code View} instances
974      *
975      * @return ViewService implementation
976      */
977     protected ViewService getViewService() {
978         return KRADServiceLocatorWeb.getViewService();
979     }
980 
981     /**
982      * The jumpToId for this form, the element with this id will be jumped to automatically
983      * when the form is loaded in the view.
984      * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the resulting page.
985      * jumpToId always takes precedence over jumpToName, if set.
986      *
987      * @return the jumpToId
988      */
989     public String getJumpToId() {
990         return this.jumpToId;
991     }
992 
993     /**
994      * @param jumpToId the jumpToId to set
995      */
996     public void setJumpToId(String jumpToId) {
997         this.jumpToId = jumpToId;
998     }
999 
1000     /**
1001      * The jumpToName for this form, the element with this name will be jumped to automatically
1002      * when the form is loaded in the view.
1003      * WARNING: jumpToId always takes precedence over jumpToName, if set.
1004      *
1005      * @return the jumpToName
1006      */
1007     public String getJumpToName() {
1008         return this.jumpToName;
1009     }
1010 
1011     /**
1012      * @param jumpToName the jumpToName to set
1013      */
1014     public void setJumpToName(String jumpToName) {
1015         this.jumpToName = jumpToName;
1016     }
1017 
1018     /**
1019      * Field to place focus on when the page loads
1020      * An empty focusId will result in focusing on the first visible input element by default.
1021      *
1022      * @return the focusId
1023      */
1024     public String getFocusId() {
1025         return this.focusId;
1026     }
1027 
1028     /**
1029      * @param focusId the focusId to set
1030      */
1031     public void setFocusId(String focusId) {
1032         this.focusId = focusId;
1033     }
1034 
1035     /**
1036      * True when the form is considered dirty (data has changed from original value), false otherwise
1037      *
1038      * <p>For most scenarios, this flag should NOT be set to true.
1039      * If this is set, it must be managed explicitly by the application.  This flag exists for marking a
1040      * form dirty from a server call, so it must be changed to false when the form is no longer considered dirty.
1041      * The krad save Action and navigate methodToCall resets this flag back to false, but any other setting of
1042      * this flag must be managed by custom configuration/methods, if custom dirtyForm management is needed.</p>
1043      *
1044      * @return true if the form is considered dirty, false otherwise
1045      */
1046     public boolean isDirtyForm() {
1047         return dirtyForm;
1048     }
1049 
1050     /**
1051      * Sets the dirtyForm flag
1052      *
1053      * <p>For most scenarios, this flag should NOT be set to true.
1054      * If this is set, it must be managed explicitly by the application.  This flag exists for marking a
1055      * form dirty from a server call, so it must be changed to false when the form is no longer considered dirty.
1056      * The krad save Action and navigate methodToCall resets this flag back to false, but any other setting of
1057      * this flag must be managed by custom configuration/methods, if custom dirtyForm management is needed.</p>
1058      *
1059      * @param dirtyForm
1060      */
1061     public void setDirtyForm(boolean dirtyForm) {
1062         this.dirtyForm = dirtyForm;
1063     }
1064 
1065     /**
1066      * Set the dirtyForm flag using a String that will be converted to boolean
1067      *
1068      * @param dirtyForm
1069      */
1070     public void setDirtyForm(String dirtyForm) {
1071         if(dirtyForm != null){
1072             this.dirtyForm = Boolean.parseBoolean(dirtyForm);
1073         }
1074     }
1075 
1076     /**
1077      * Indicates whether the view is rendered within a lightbox
1078      *
1079      * <p>
1080      * Some discussion (for example how a close button behaves) need to change based on whether the
1081      * view is rendered within a lightbox or the standard browser window. This boolean is true when it is
1082      * within a lightbox
1083      * </p>
1084      *
1085      * @return boolean true if view is rendered within a lightbox, false if not
1086      */
1087     public boolean isRenderedInLightBox() {
1088         return this.renderedInLightBox;
1089     }
1090 
1091     /**
1092      * Setter for the rendered within lightbox indicator
1093      *
1094      * @param renderedInLightBox
1095      */
1096     public void setRenderedInLightBox(boolean renderedInLightBox) {
1097         this.renderedInLightBox = renderedInLightBox;
1098     }
1099 
1100     /**
1101      * Indicates whether the view is rendered within an iframe (this setting must be passed to the View on the url)
1102      *
1103      * @return boolean true if view is rendered within a iframe, false if not
1104      */
1105     public boolean isRenderedInIframe() {
1106         return renderedInIframe;
1107     }
1108 
1109     /**
1110      * @see org.kuali.rice.krad.web.form.UifFormBase#isRenderedInIframe()
1111      */
1112     public void setRenderedInIframe(boolean renderedInIframe) {
1113         this.renderedInIframe = renderedInIframe;
1114     }
1115 
1116     /**
1117      * @see org.kuali.rice.krad.uif.view.ViewModel#getGrowlScript()
1118      */
1119     @Override
1120     public String getGrowlScript() {
1121         return growlScript;
1122     }
1123 
1124     /**
1125      * @see org.kuali.rice.krad.uif.view.ViewModel#setGrowlScript(String)
1126      */
1127     @Override
1128     public void setGrowlScript(String growlScript) {
1129         this.growlScript = growlScript;
1130     }
1131 
1132     /**
1133      * @see org.kuali.rice.krad.uif.view.ViewModel#getState()
1134      */
1135     @Override
1136     public String getState() {
1137         return state;
1138     }
1139 
1140     /**
1141      * @see org.kuali.rice.krad.uif.view.ViewModel#setState(String)
1142      */
1143     @Override
1144     public void setState(String state) {
1145         this.state = state;
1146     }
1147 
1148     /**
1149      * @see org.kuali.rice.krad.uif.view.ViewModel#isAjaxRequest()
1150      */
1151     @Override
1152     public boolean isAjaxRequest() {
1153         return ajaxRequest;
1154     }
1155 
1156     /**
1157      * @see org.kuali.rice.krad.uif.view.ViewModel#setAjaxRequest(boolean)
1158      */
1159     @Override
1160     public void setAjaxRequest(boolean ajaxRequest) {
1161         this.ajaxRequest = ajaxRequest;
1162     }
1163 
1164     /**
1165      * @see org.kuali.rice.krad.uif.view.ViewModel#getAjaxReturnType()
1166      */
1167     @Override
1168     public String getAjaxReturnType() {
1169         return ajaxReturnType;
1170     }
1171 
1172     /**
1173      * @see org.kuali.rice.krad.uif.view.ViewModel#setAjaxReturnType(String)
1174      */
1175     @Override
1176     public void setAjaxReturnType(String ajaxReturnType) {
1177         this.ajaxReturnType = ajaxReturnType;
1178     }
1179 
1180     /**
1181      * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateComponentRequest()
1182      */
1183     @Override
1184     public boolean isUpdateComponentRequest() {
1185         return isAjaxRequest() && StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals(
1186                 UifConstants.AjaxReturnTypes.UPDATECOMPONENT.getKey());
1187     }
1188 
1189     /**
1190      * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateDialogRequest()
1191      */
1192     @Override
1193     public boolean isUpdateDialogRequest() {
1194         return isAjaxRequest() && StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals(
1195                 UifConstants.AjaxReturnTypes.UPDATEDIALOG.getKey());
1196     }
1197 
1198     /**
1199      * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdatePageRequest()
1200      */
1201     @Override
1202     public boolean isUpdatePageRequest() {
1203         return StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals(
1204                 UifConstants.AjaxReturnTypes.UPDATEPAGE.getKey());
1205     }
1206 
1207     /**
1208      * @see org.kuali.rice.krad.uif.view.ViewModel#isUpdateNoneRequest()
1209      */
1210     @Override
1211     public boolean isUpdateNoneRequest() {
1212         //return isAjaxRequest() && StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals(
1213         //        UifConstants.AjaxReturnTypes.UPDATENONE.getKey());
1214         return StringUtils.isNotBlank(getAjaxReturnType()) && getAjaxReturnType().equals(
1215                 UifConstants.AjaxReturnTypes.UPDATENONE.getKey());
1216     }
1217 
1218     /**
1219      * @see org.kuali.rice.krad.uif.view.ViewModel#isJsonRequest()
1220      */
1221     @Override
1222     public boolean isJsonRequest() {
1223         return StringUtils.isNotBlank(getRequestJsonTemplate());
1224     }
1225 
1226     /**
1227      * @see org.kuali.rice.krad.uif.view.ViewModel#getRequestJsonTemplate()
1228      */
1229     @Override
1230     public String getRequestJsonTemplate() {
1231         return requestJsonTemplate;
1232     }
1233 
1234     /**
1235      * @see org.kuali.rice.krad.uif.view.ViewModel#setRequestJsonTemplate
1236      */
1237     @Override
1238     public void setRequestJsonTemplate(String requestJsonTemplate) {
1239         this.requestJsonTemplate = requestJsonTemplate;
1240     }
1241 
1242     /**
1243      * {@inheritDoc}
1244      */
1245     @Override
1246     public boolean isCollectionPagingRequest() {
1247         return collectionPagingRequest;
1248     }
1249 
1250     /**
1251      * {@inheritDoc}
1252      */
1253     @Override
1254     public void setCollectionPagingRequest(boolean collectionPagingRequest) {
1255         this.collectionPagingRequest = collectionPagingRequest;
1256     }
1257 
1258     /**
1259      * Used by the dialog framework to set the dialog id for a return dialog call (when the server has
1260      * triggered a dialog).
1261      *
1262      * <p>Note this is a request only property. On a return call the value for this gets pulled and used to
1263      * create an entry in {@link UifFormBase#getDialogResponses()}</p>
1264      *
1265      * @return String id for the dialog being returned from
1266      */
1267     public String getReturnDialogId() {
1268         return returnDialogId;
1269     }
1270 
1271     /**
1272      * @see UifFormBase#getReturnDialogId()
1273      */
1274     public void setReturnDialogId(String returnDialogId) {
1275         this.returnDialogId = returnDialogId;
1276     }
1277 
1278     /**
1279      * Used by the dialog framework to set the dialog response for a return dialog call (when the server has
1280      * triggered a dialog).
1281      *
1282      * <p>Note this is a request only property. On a return call the value for this gets pulled and used to
1283      * create an entry in {@link UifFormBase#getDialogResponses()}</p>
1284      *
1285      * @return String response for the dialog being returned from
1286      */
1287     public String getReturnDialogResponse() {
1288         return returnDialogResponse;
1289     }
1290 
1291     /**
1292      * @see UifFormBase#getReturnDialogResponse()
1293      */
1294     public void setReturnDialogResponse(String returnDialogResponse) {
1295         this.returnDialogResponse = returnDialogResponse;
1296     }
1297 
1298     /**
1299      * {@inheritDoc}
1300      */
1301     @Override
1302     public Map<String, String> getDialogExplanations() {
1303         return dialogExplanations;
1304     }
1305 
1306     /**
1307      * {@inheritDoc}
1308      */
1309     @Override
1310     public void setDialogExplanations(Map<String, String> dialogExplanations) {
1311         this.dialogExplanations = dialogExplanations;
1312     }
1313 
1314     /**
1315      * {@inheritDoc}
1316      */
1317     @Override
1318     public Map<String, DialogResponse> getDialogResponses() {
1319         return dialogResponses;
1320     }
1321 
1322     /**
1323      * {@inheritDoc}
1324      */
1325     @Override
1326     public DialogResponse getDialogResponse(String dialogId) {
1327         if ((dialogResponses != null) && dialogResponses.containsKey(dialogId)) {
1328             return dialogResponses.get(dialogId);
1329         }
1330 
1331         return null;
1332     }
1333 
1334     /**
1335      * {@inheritDoc}
1336      */
1337     @Override
1338     public void setDialogResponses(Map<String, DialogResponse> dialogResponses) {
1339         this.dialogResponses = dialogResponses;
1340     }
1341 
1342     /**
1343      * @see org.kuali.rice.krad.uif.view.ViewModel#getExtensionData()
1344      */
1345     @Override
1346     public Map<String, Object> getExtensionData() {
1347         return extensionData;
1348     }
1349 
1350     /**
1351      * {@inheritDoc}
1352      */
1353     @Override
1354     public void setExtensionData(Map<String, Object> extensionData) {
1355         this.extensionData = extensionData;
1356     }
1357 
1358     /**
1359      * A generic map for query parameters
1360      *
1361      * @return Map<String, String>
1362      */
1363     public Map<String, String> getQueryParameters() {
1364         return queryParameters;
1365     }
1366 
1367     /**
1368      * Setter for the generic query parameters
1369      *
1370      * @param queryParameters
1371      */
1372     public void setQueryParameters(Map<String, String> queryParameters) {
1373         this.queryParameters = queryParameters;
1374     }
1375 
1376     /**
1377      * The {@code List} that contains all newly added items for the collections on the model
1378      *
1379      * <p>
1380      * This list contains the new items for all the collections on the model.
1381      * </p>
1382      *
1383      * @return List of the newly added item lists
1384      */
1385     public List getAddedCollectionItems() {
1386         return addedCollectionItems;
1387     }
1388 
1389     /**
1390      * Setter for the newly added item list
1391      *
1392      * @param addedCollectionItems
1393      */
1394     public void setAddedCollectionItems(List addedCollectionItems) {
1395         this.addedCollectionItems = addedCollectionItems;
1396     }
1397 
1398     /**
1399      * Indicates whether an collection item has been newly added
1400      *
1401      * <p>
1402      * Tests collection items against the list of newly added items on the model. This list gets cleared when the view
1403      * is submitted and the items are persisted.
1404      * </p>
1405      *
1406      * @param item - the item to test against list of newly added items
1407      * @return boolean true if the item has been newly added
1408      */
1409     public boolean isAddedCollectionItem(Object item) {
1410         return addedCollectionItems.contains(item);
1411     }
1412 
1413     @Override
1414     public String toString() {
1415         StringBuilder builder = new StringBuilder();
1416         builder.append( getClass().getSimpleName() ).append(" [viewId=").append(this.viewId).append(", viewName=").append(this.viewName)
1417                 .append(", viewTypeName=").append(this.viewTypeName).append(", pageId=").append(this.pageId)
1418                 .append(", methodToCall=").append(this.methodToCall).append(", formKey=").append(this.formKey)
1419                 .append(", requestedFormKey=").append(this.requestedFormKey).append("]");
1420         return builder.toString();
1421     }
1422 }