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 }