View Javadoc

1   /**
2    * Copyright 2005-2011 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 org.apache.commons.lang.StringUtils;
19  import org.codehaus.jackson.map.ObjectMapper;
20  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
21  import org.kuali.rice.krad.uif.UifConstants;
22  import org.kuali.rice.krad.uif.UifParameters;
23  import org.kuali.rice.krad.uif.view.History;
24  import org.kuali.rice.krad.uif.view.View;
25  import org.kuali.rice.krad.uif.service.ViewService;
26  import org.kuali.rice.krad.uif.view.ViewModel;
27  import org.kuali.rice.krad.util.KRADUtils;
28  import org.springframework.web.multipart.MultipartFile;
29  import org.kuali.rice.krad.uif.UifConstants.ViewType;
30  
31  import javax.servlet.http.HttpServletRequest;
32  import java.io.IOException;
33  import java.util.ArrayList;
34  import java.util.HashMap;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Properties;
38  import java.util.Set;
39  import java.util.UUID;
40  
41  /**
42   * Base form class for views within the KRAD User Interface Framework
43   *
44   * <p>
45   * Holds properties necessary to determine the <code>View</code> instance that
46   * will be used to render the UI
47   * </p>
48   *
49   * @author Kuali Rice Team (rice.collab@kuali.org)
50   */
51  public class UifFormBase implements ViewModel {
52      private static final long serialVersionUID = 8432543267099454434L;
53  
54      // current view
55      protected String viewId;
56      protected String viewName;
57      protected ViewType viewTypeName;
58      protected String pageId;
59      protected String methodToCall;
60      protected String formKey;
61      protected String jumpToId;
62      protected String jumpToName;
63      protected String focusId;
64      protected String formPostUrl;
65  
66      protected boolean defaultsApplied;
67  
68      protected View view;
69      protected View previousView;
70  
71      protected Map<String, String> viewRequestParameters;
72      protected List<String> readOnlyFieldsList;
73  
74      protected Map<String, Object> newCollectionLines;
75      protected Map<String, String> actionParameters;
76      protected Map<String, Object> clientStateForSyncing;
77      protected Map<String, Set<String>> selectedCollectionLines;
78  
79      protected MultipartFile attachmentFile;
80  
81      // navigation
82      protected String returnLocation;
83      protected String returnFormKey;
84  
85      protected History formHistory;
86  
87      protected boolean renderFullView;
88      protected boolean validateDirty;
89  
90      public UifFormBase() {
91          formKey = generateFormKey();
92          renderFullView = true;
93          defaultsApplied = false;
94  
95          readOnlyFieldsList = new ArrayList<String>();
96          viewRequestParameters = new HashMap<String, String>();
97          newCollectionLines = new HashMap<String, Object>();
98          actionParameters = new HashMap<String, String>();
99          clientStateForSyncing = new HashMap<String, Object>();
100         selectedCollectionLines = new HashMap<String, Set<String>>();
101     }
102 
103     /**
104      * Creates the unique id used to store this "conversation" in the session.
105      * The default method generates a java UUID.
106      *
107      * @return
108      */
109     protected String generateFormKey() {
110         return UUID.randomUUID().toString();
111     }
112 
113     /**
114      * Called after Spring binds the request to the form and before the
115      * controller method is invoked.
116      *
117      * @param request - request object containing the query parameters
118      */
119     public void postBind(HttpServletRequest request) {
120         // default form post URL to request URL
121         formPostUrl = request.getRequestURL().toString();
122 
123         // get any sent client view state and parse into map
124         if (request.getParameterMap().containsKey(UifParameters.CLIENT_VIEW_STATE)) {
125             String clientStateJSON = request.getParameter(UifParameters.CLIENT_VIEW_STATE);
126             if (StringUtils.isNotBlank(clientStateJSON)) {
127                 // change single quotes to double quotes (necessary because the reverse was done for sending)
128                 clientStateJSON = StringUtils.replace(clientStateJSON, "'", "\"");
129 
130                 ObjectMapper mapper = new ObjectMapper();
131                 try {
132                     clientStateForSyncing = mapper.readValue(clientStateJSON, Map.class);
133                 } catch (IOException e) {
134                     throw new RuntimeException("Unable to decode client side state JSON", e);
135                 }
136             }
137         }
138 
139         // populate read only fields list
140         if (request.getParameter(UifParameters.READ_ONLY_FIELDS) != null) {
141             String readOnlyFields = request.getParameter(UifParameters.READ_ONLY_FIELDS);
142             setReadOnlyFieldsList(KRADUtils.convertStringParameterToList(readOnlyFields));
143         }
144     }
145 
146     /**
147      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewId()
148      */
149     public String getViewId() {
150         return this.viewId;
151     }
152 
153     /**
154      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewId(java.lang.String)
155      */
156     public void setViewId(String viewId) {
157         this.viewId = viewId;
158     }
159 
160     /**
161      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewName()
162      */
163     public String getViewName() {
164         return this.viewName;
165     }
166 
167     /**
168      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewName(java.lang.String)
169      */
170     public void setViewName(String viewName) {
171         this.viewName = viewName;
172     }
173 
174     /**
175      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewTypeName()
176      */
177     public ViewType getViewTypeName() {
178         return this.viewTypeName;
179     }
180 
181     /**
182      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewTypeName(org.kuali.rice.krad.uif.UifConstants.ViewType)
183      */
184     public void setViewTypeName(ViewType viewTypeName) {
185         this.viewTypeName = viewTypeName;
186     }
187 
188     /**
189      * @see org.kuali.rice.krad.uif.view.ViewModel#getPageId()
190      */
191     public String getPageId() {
192         return this.pageId;
193     }
194 
195     /**
196      * @see org.kuali.rice.krad.uif.view.ViewModel#setPageId(java.lang.String)
197      */
198     public void setPageId(String pageId) {
199         this.pageId = pageId;
200     }
201 
202     /**
203      * @see org.kuali.rice.krad.uif.view.ViewModel#getFormPostUrl()
204      */
205     public String getFormPostUrl() {
206         return this.formPostUrl;
207     }
208 
209     /**
210      * @see org.kuali.rice.krad.uif.view.ViewModel#setFormPostUrl(java.lang.String)
211      */
212     public void setFormPostUrl(String formPostUrl) {
213         this.formPostUrl = formPostUrl;
214     }
215 
216     public String getReturnLocation() {
217         return this.returnLocation;
218     }
219 
220     public void setReturnLocation(String returnLocation) {
221         this.returnLocation = returnLocation;
222     }
223 
224     public String getReturnFormKey() {
225         return this.returnFormKey;
226     }
227 
228     public void setReturnFormKey(String returnFormKey) {
229         this.returnFormKey = returnFormKey;
230     }
231 
232     /**
233      * Identifies the controller method that should be invoked to fulfill a
234      * request. The value will be matched up against the 'params' setting on the
235      * <code>RequestMapping</code> annotation for the controller method
236      *
237      * @return String method to call
238      */
239     public String getMethodToCall() {
240         return this.methodToCall;
241     }
242 
243     /**
244      * Setter for the method to call
245      *
246      * @param methodToCall
247      */
248     public void setMethodToCall(String methodToCall) {
249         this.methodToCall = methodToCall;
250     }
251 
252     /**
253      * @see org.kuali.rice.krad.uif.view.ViewModel#getViewRequestParameters()
254      */
255     public Map<String, String> getViewRequestParameters() {
256         return this.viewRequestParameters;
257     }
258 
259     /**
260      * @see org.kuali.rice.krad.uif.view.ViewModel#setViewRequestParameters(java.util.Map<java.lang.String,java.lang.String>)
261      */
262     public void setViewRequestParameters(Map<String, String> viewRequestParameters) {
263         this.viewRequestParameters = viewRequestParameters;
264     }
265 
266     /**
267      * @see org.kuali.rice.krad.uif.view.ViewModel#getReadOnlyFieldsList()
268      */
269     public List<String> getReadOnlyFieldsList() {
270         return readOnlyFieldsList;
271     }
272 
273     /**
274      * @see org.kuali.rice.krad.uif.view.ViewModel#setReadOnlyFieldsList(java.util.List<java.lang.String>)
275      */
276     public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) {
277         this.readOnlyFieldsList = readOnlyFieldsList;
278     }
279 
280     /**
281      * @see org.kuali.rice.krad.uif.view.ViewModel#getNewCollectionLines()
282      */
283     public Map<String, Object> getNewCollectionLines() {
284         return this.newCollectionLines;
285     }
286 
287     /**
288      * @see org.kuali.rice.krad.uif.view.ViewModel#setNewCollectionLines(java.util.Map<java.lang.String,java.lang.Object>)
289      */
290     public void setNewCollectionLines(Map<String, Object> newCollectionLines) {
291         this.newCollectionLines = newCollectionLines;
292     }
293 
294     /**
295      * @see org.kuali.rice.krad.uif.view.ViewModel#getActionParameters()
296      */
297     public Map<String, String> getActionParameters() {
298         return this.actionParameters;
299     }
300 
301     /**
302      * Returns the action parameters map as a <code>Properties</code> instance
303      *
304      * @return Properties action parameters
305      */
306     public Properties getActionParametersAsProperties() {
307         Properties actionProperties = new Properties();
308 
309         if (actionParameters != null) {
310             for (Map.Entry<String, String> actionParameter : actionParameters.entrySet()) {
311                 actionProperties.put(actionParameter.getKey(), actionParameter.getValue());
312             }
313         }
314 
315         return actionProperties;
316     }
317 
318     /**
319      * @see org.kuali.rice.krad.uif.view.ViewModel#setActionParameters(java.util.Map<java.lang.String,java.lang.String>)
320      */
321     public void setActionParameters(Map<String, String> actionParameters) {
322         this.actionParameters = actionParameters;
323     }
324 
325     /**
326      * Retrieves the value for the given action parameter, or empty string if
327      * not found
328      *
329      * @param actionParameterName - name of the action parameter to retrieve value for
330      * @return String parameter value or empty string
331      */
332     public String getActionParamaterValue(String actionParameterName) {
333         if ((actionParameters != null) && actionParameters.containsKey(actionParameterName)) {
334             return actionParameters.get(actionParameterName);
335         }
336 
337         return "";
338     }
339 
340     /**
341      * Returns the action event that was sent in the action parameters (if any)
342      *
343      * <p>
344      * The action event is a special action parameter that can be sent to indicate a type of action being taken. This
345      * can be looked at by the view or components to render differently
346      * </p>
347      *
348      * TODO: make sure action parameters are getting reinitialized on each request
349      *
350      * @return String action event name or blank if action event was not sent
351      */
352     public String getActionEvent() {
353         if ((actionParameters != null) && actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT)) {
354             return actionParameters.get(UifConstants.UrlParams.ACTION_EVENT);
355         }
356 
357         return "";
358     }
359 
360     /**
361      * @see org.kuali.rice.krad.uif.view.ViewModel#getClientStateForSyncing()
362      */
363     public Map<String, Object> getClientStateForSyncing() {
364         return clientStateForSyncing;
365     }
366 
367     /**
368      * @see org.kuali.rice.krad.uif.view.ViewModel#getSelectedCollectionLines()
369      */
370     public Map<String, Set<String>> getSelectedCollectionLines() {
371         return selectedCollectionLines;
372     }
373 
374     /**
375      * @see org.kuali.rice.krad.uif.view.ViewModel#setSelectedCollectionLines(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)
376      */
377     public void setSelectedCollectionLines(Map<String, Set<String>> selectedCollectionLines) {
378         this.selectedCollectionLines = selectedCollectionLines;
379     }
380 
381     /**
382      * Key string that identifies the form instance in session storage
383      *
384      * <p>
385      * When the view is posted, the previous form instance is retrieved and then
386      * populated from the request parameters. This key string is retrieve the
387      * session form from the session service
388      * </p>
389      *
390      * @return String form session key
391      */
392     public String getFormKey() {
393         return this.formKey;
394     }
395 
396     /**
397      * Setter for the form's session key
398      *
399      * @param formKey
400      */
401     public void setFormKey(String formKey) {
402         this.formKey = formKey;
403     }
404 
405     /**
406      * @see org.kuali.rice.krad.uif.view.ViewModel#isDefaultsApplied()
407      */
408     public boolean isDefaultsApplied() {
409         return this.defaultsApplied;
410     }
411 
412     /**
413      * @see org.kuali.rice.krad.uif.view.ViewModel#setDefaultsApplied(boolean)
414      */
415     public void setDefaultsApplied(boolean defaultsApplied) {
416         this.defaultsApplied = defaultsApplied;
417     }
418 
419     /**
420      * Holder for files that are attached through the view
421      *
422      * @return MultipartFile representing the attachment
423      */
424     public MultipartFile getAttachmentFile() {
425         return this.attachmentFile;
426     }
427 
428     /**
429      * Setter for the form's attachment file
430      *
431      * @param attachmentFile
432      */
433     public void setAttachmentFile(MultipartFile attachmentFile) {
434         this.attachmentFile = attachmentFile;
435     }
436 
437     /**
438      * @return the renderFullView
439      */
440     public boolean isRenderFullView() {
441         return this.renderFullView;
442     }
443 
444     /**
445      * @param renderFullView
446      */
447     public void setRenderFullView(boolean renderFullView) {
448         this.renderFullView = renderFullView;
449     }
450 
451     /**
452      * View instance associated with the form. Used to render the user interface
453      *
454      * @return View
455      */
456     public View getView() {
457         return this.view;
458     }
459 
460     /**
461      * Setter for the view instance
462      *
463      * @param view
464      */
465     public void setView(View view) {
466         this.view = view;
467     }
468 
469     /**
470      * View instance for the page that made a request. Since a new view instance
471      * gets initialized for each request before the controller logic is invoked,
472      * any state about the previous view is lost. This could be needed to read
473      * metadata from the view for such things as collection processing. When
474      * this is necessary the previous view instance can be retrieved
475      *
476      * @return View instance
477      */
478     public View getPreviousView() {
479         return this.previousView;
480     }
481 
482     /**
483      * Setter for the previous view instance
484      *
485      * @param previousView
486      */
487     public void setPreviousView(View previousView) {
488         this.previousView = previousView;
489     }
490 
491     /**
492      * Instance of the <code>ViewService</code> that can be used to retrieve
493      * <code>View</code> instances
494      *
495      * @return ViewService implementation
496      */
497     protected ViewService getViewService() {
498         return KRADServiceLocatorWeb.getViewService();
499     }
500 
501     /**
502      * The jumpToId for this form, the element with this id will be jumped to automatically
503      * when the form is loaded in the view.
504      * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the resulting page.
505      * jumpToId always takes precedence over jumpToName, if set.
506      *
507      * @return the jumpToId
508      */
509     public String getJumpToId() {
510         return this.jumpToId;
511     }
512 
513     /**
514      * @param jumpToId the jumpToId to set
515      */
516     public void setJumpToId(String jumpToId) {
517         this.jumpToId = jumpToId;
518     }
519 
520     /**
521      * The jumpToName for this form, the element with this name will be jumped to automatically
522      * when the form is loaded in the view.
523      * WARNING: jumpToId always takes precedence over jumpToName, if set.
524      *
525      * @return the jumpToName
526      */
527     public String getJumpToName() {
528         return this.jumpToName;
529     }
530 
531     /**
532      * @param jumpToName the jumpToName to set
533      */
534     public void setJumpToName(String jumpToName) {
535         this.jumpToName = jumpToName;
536     }
537 
538     /**
539      * Field to place focus on when the page loads
540      * An empty focusId will result in focusing on the first visible input element by default.
541      *
542      * @return the focusId
543      */
544     public String getFocusId() {
545         return this.focusId;
546     }
547 
548     /**
549      * @param focusId the focusId to set
550      */
551     public void setFocusId(String focusId) {
552         this.focusId = focusId;
553     }
554 
555     /**
556      * History parameter representing the History of views that have come before the
557      * viewing of the current view
558      *
559      * <p>
560      * Used for breadcrumb widget generation on the view and also for navigating back
561      * to previous or hub locations
562      * </p>
563      *
564      * @return History instance giving current history
565      */
566     public History getFormHistory() {
567         return formHistory;
568     }
569 
570     /**
571      * Setter for the current History object
572      *
573      * @param history the history to set
574      */
575     public void setFormHistory(History history) {
576         this.formHistory = history;
577     }
578 
579     /**
580      * Indicates whether the form should be validated for dirtyness
581      *
582      * <p>
583      * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the
584      * InputFields will be validated on refresh, navigate, cancel or close Action or on form
585      * unload and if dirty, displays a message and user can decide whether to continue with
586      * the action or stay on the form
587      * </p>
588      *
589      * @return boolean true if dirty validation should be enabled
590      */
591     public boolean isValidateDirty() {
592         return this.validateDirty;
593     }
594 
595     /**
596      * Setter for dirty validation indicator
597      *
598      * @param validateDirty
599      */
600     public void setValidateDirty(boolean validateDirty) {
601         this.validateDirty = validateDirty;
602     }
603 
604 }